KLUPD::CoreError KLUPD::UpdateInfo::parse(const Path &path, FileInfo &fileInfo, const ChangeStateCheck &changeStateCheck, const FileVector &localFilesToCheckAgainst, const bool suppressSuccessLogMessages) { // index is already parsed, files already attached if(fileAlreadyParsed(fileInfo)) return CORE_NO_ERROR; const Path fullFileName = path + fileInfo.m_filename; if(!suppressSuccessLogMessages) TRACE_MESSAGE2("Parsing XML index file '%S'", fullFileName.toWideChar()); std::vector<unsigned char> buffer; const CoreError readFileResult = LocalFile(fullFileName, pLog).read(buffer); if(!KLUPD::isSuccess(readFileResult)) { TRACE_MESSAGE3("Failed to read XML index file '%S', result '%S'", fullFileName.toWideChar(), KLUPD::toString(readFileResult).toWideChar()); return readFileResult; } if(buffer.empty()) { TRACE_MESSAGE3("Index XML file '%S' is corrupted, file size is %d", fullFileName.toWideChar(), buffer.size()); return CORE_UPDATE_DESCRIPTION_DAMAGED; } // a file list obtained from XML FileVector fileList; IndexFileXMLParser xmler(fileInfo.m_filename.m_value, fileList, m_signature6Checker, fileInfo.m_relativeURLPath, m_retranslationMode, m_callbacks, pLog); XmlReader xmlReader(reinterpret_cast<const char *>(&buffer[0]), buffer.size()); if(!xmler.parseXMLRecursively(xmlReader, 0) || fileList.empty()) { TRACE_MESSAGE3("\tXML file parse error '%S', file number found %d", fullFileName.toWideChar(), fileList.size()); return CORE_UPDATE_DESCRIPTION_DAMAGED; } m_parsedIndexCache.push_back(fileInfo); xmler.GetUpdateDate(fileInfo.m_strUpdateDate); xmler.GetBlackDate(fileInfo.m_strBlackDate); // save variables to write into settings storage std::vector<UpdatedSettings> updatedSettings = xmler.updatedSettings(); m_updatedSettings.insert(m_updatedSettings.end(), updatedSettings.begin(), updatedSettings.end()); // copy to match list only those items which suits download criteria for(FileVector::iterator fileIter = fileList.begin(); fileIter != fileList.end(); ++fileIter) { // check download filters criteria should be performed NoCaseString reasonNotMatch; if(!matchesSettings(reasonNotMatch, *fileIter)) { if(!suppressSuccessLogMessages) { TRACE_MESSAGE3("\tFile filtered, download criteria does not matches: '%S', %S", reasonNotMatch.toWideChar(), fileIter->toString().toWideChar()); } continue; } // check download mandatory criteria reasonNotMatch.erase(); if(!isEntryRequired(reasonNotMatch, *fileIter, m_filterFlags)) { if(!suppressSuccessLogMessages) { TRACE_MESSAGE3("\tFile filtered, mandatory criteria does not matches: '%S', %S", reasonNotMatch.toWideChar(), fileIter->toString().toWideChar()); } continue; } // setup transaction folders fileIter->m_transactionInformation.m_currentLocation = m_callbacks.productFolder(*fileIter, m_retranslationMode); fileIter->m_transactionInformation.m_newLocation = m_callbacks.temporaryFolder(*fileIter); NoCaseString statusExplanations; fileIter->m_transactionInformation.m_changeStatus = getFileStatusAgainstLocal(*fileIter, changeStateCheck, localFilesToCheckAgainst, statusExplanations); // insert file with filtering duplicates bool fileDuplicate = false; // insert black list into the beginning of list, because it should be checked before downloading other bases if(fileIter->m_type == FileInfo::blackList) m_matchFileList.insertNewInTheBeginOfListOrUpdateTheSame(*fileIter, *fileIter, fileDuplicate, m_retranslationMode); else m_matchFileList.insertNewOrUpdateTheSame(*fileIter, *fileIter, fileDuplicate, m_retranslationMode); if(!suppressSuccessLogMessages) { // to avoid empty brackets output to trace if(!statusExplanations.empty()) statusExplanations = NoCaseString(L"(") + statusExplanations + L")"; if(fileDuplicate) { TRACE_MESSAGE3("\tDuplicate file information updated: %S %S", fileIter->toString().toWideChar(), statusExplanations.toWideChar()); } else { TRACE_MESSAGE3("\tFile matches download criteria: %S %S", fileIter->toString().toWideChar(), statusExplanations.toWideChar()); } } } return CORE_NO_ERROR; }
KLUPD::FileInfo::ChangeStatus KLUPD::UpdateInfo::getFileStatusAgainstLocal(const FileInfo &etalon, const ChangeStateCheck &changeStateCheck, const FileVector &localFilesToCheckAgainst, NoCaseString &statusExplanations)const { if(changeStateCheck == noStateChangeCheck) return FileInfo::unchanged; statusExplanations.erase(); LocalFile fileInProductFolder(m_callbacks.productFolder(etalon, m_retranslationMode) + etalon.m_filename); ////////////////////////////////////////////////////////////////////////// // check if file in product folder exists if(!fileInProductFolder.exists()) { statusExplanations = L"original files does not exist"; return FileInfo::added; } // inlined file is already downloaded together with index file, can be only compared if it changed if(etalon.isInlined()) { std::vector<unsigned char> buffer; const CoreError readInlinedFileResult = fileInProductFolder.read(buffer); if(!isSuccess(readInlinedFileResult)) { TRACE_MESSAGE3("Failed to detect change state for inlined file '%S', file operation error '%S'", fileInProductFolder.m_name.toWideChar(), toString(readInlinedFileResult).toWideChar()); statusExplanations = L"inlined file can not be read"; return FileInfo::added; } if(buffer == etalon.m_inlinedContent) { statusExplanations = L"inlined file is not changed"; return FileInfo::unchanged; } else { statusExplanations = L"inlined file is not modified"; return FileInfo::modified; } } ////////////////////////////////////////////////////////////////////////// // check against signature 5 if(!etalon.m_signature5.empty()) { if(checkInsideSignature5AgainstEtalon(fileInProductFolder.m_name, etalon.m_signature5, pLog)) { statusExplanations = L"signature 5 is not changed"; return FileInfo::unchanged; } else { statusExplanations = L"signature 5 is changed"; return FileInfo::modified; } } ////////////////////////////////////////////////////////////////////////// // check file against md5 if(!etalon.m_md5.empty()) { std::vector<unsigned char> md5; if(!calcMD5Hash(fileInProductFolder.m_name, md5)) { statusExplanations = L"failed to calculate md5 hash"; return FileInfo::added; } if(md5 == etalon.m_md5) { statusExplanations = L"md5 unchanged"; return FileInfo::unchanged; } else { statusExplanations = L"md5 changed"; return FileInfo::modified; } } ////////////////////////////////////////////////////////////////////////// // check date statusExplanations += NoCaseString(L"date from index '") + etalon.m_dateFromIndex + L"', " + (localFilesToCheckAgainst.empty() ? L"local bases are not consistent" : L"local bases are consistent"); if(!etalon.m_dateFromIndex.empty() // date check is only performed if file presents in consistent local file set, // otherwise file may belong to other Update set and must be updated && !localFilesToCheckAgainst.empty()) { FileInfo::ChangeStatus modifiedIfDatesAreIgnored = FileInfo::unchanged; // check if index date is newer is only performed for Kaspersky sources if(changeStateCheck == checkStateButIgnoreDate) { modifiedIfDatesAreIgnored = FileInfo::modified; statusExplanations = L", dates are ignored for user-specified sources"; } FileInfo localConsistentFile; if(localFilesToCheckAgainst.findTheSameFile(etalon, localConsistentFile, m_retranslationMode)) { bool bIndex = etalon.isIndex(); const NoCaseString& strLocalFileDate = bIndex ? localConsistentFile.m_strUpdateDate : localConsistentFile.m_dateFromIndex; NoCaseString strFileType(bIndex ? L"index" : L"non-index"); // for trace if(!strLocalFileDate.empty()) { // if expected date on source is less, then file is skipped unsigned long nEtalonDate = updateDateStringToSequenceNumber(etalon.m_dateFromIndex); unsigned long nLocalFileDate = updateDateStringToSequenceNumber(strLocalFileDate); if(nEtalonDate < nLocalFileDate) { statusExplanations += NoCaseString(L", ") + FileInfo::toString(modifiedIfDatesAreIgnored).toWideChar() + L" " + strFileType + L" file is found in local consistent set with date '" + localConsistentFile.m_dateFromIndex + L"'"; return modifiedIfDatesAreIgnored; } else if( bIndex || nEtalonDate > nLocalFileDate) { statusExplanations += NoCaseString(L", modified ") + strFileType + L" file is found in local consistent set, date from file '" + strLocalFileDate + L"'"; return FileInfo::modified; } else statusExplanations += NoCaseString(L", ") + strFileType + L" file is found in local consistent set with same date"; } else statusExplanations += NoCaseString(L", ") + strFileType + L" file is found in local consistent set, but there is no date in index specified"; } else statusExplanations += L", file is not found in local consistent set"; } ////////////////////////////////////////////////////////////////////////// // check against signature 6 bool insideSignature = false; NoCaseString errorMessage; if(!m_signature6Checker.checkSignature(fileInProductFolder.m_name, insideSignature, errorMessage)) { statusExplanations += NoCaseString(L", signature 6 check changed (") + errorMessage + L")"; return FileInfo::modified; } // file may contain inside signature6, then there is no way to determine whether // file is different on source, and that is why must always be downloaded if(insideSignature) { statusExplanations += L", inside signature 6 check unchanged (file needs being downloaded)"; return FileInfo::modified; } else { statusExplanations += L", signature 6 check unchanged"; return FileInfo::unchanged; } }