bool Ini_UpdaterLists::readSingleFileInfoRollback(const TCHAR *iniFileName, TCHAR *fileSectionName, FileInfo &file) { if(!iniFileName || (*iniFileName == 0)) { TRACE_MESSAGE("Read rollback file information error: configuration file name is not specified"); return false; } if(!fileSectionName) { TRACE_MESSAGE("Read rollback file information error: configuration section is not specified"); return false; } TCHAR buffer[MAX_STR_BUFF + 1] = _T(""); // file name GetPrivateProfileString(fileSectionName, STRING(SS_KEY_RecentFileName).c_str(), _T(UNKNOWN_STRING), buffer, MAX_STR_BUFF, iniFileName); if(!_tcscmp(buffer, _T(UNKNOWN_STRING))) { TRACE_MESSAGE2("Read rollback file information error: no '%s' value found", STRING(SS_KEY_RecentFileName).to_string().c_str()); return false; } file.m_filename = buffer; // local path GetPrivateProfileString(fileSectionName, STRING(SS_KEY_RecentLocalPath).c_str(), _T(UNKNOWN_STRING), buffer, MAX_STR_BUFF, iniFileName); if(!_tcscmp(buffer, _T(UNKNOWN_STRING))) { TRACE_MESSAGE2("Read rollback file information error: no '%s' value found", STRING(SS_KEY_RecentLocalPath).to_string().c_str()); return false; } file.m_localPath = buffer; // change status GetPrivateProfileString(fileSectionName, STRING(SS_KEY_ChangeStatus).c_str(), _T(UNKNOWN_STRING), buffer, MAX_STR_BUFF, iniFileName); if(!_tcscmp(buffer, _T(UNKNOWN_STRING))) { TRACE_MESSAGE2("Read rollback file information error: no '%s' value found", STRING(SS_KEY_ChangeStatus).to_string().c_str()); return false; } file.m_rollbackChange = buffer; // md5 for consistency check GetPrivateProfileString(fileSectionName, STRING(kayw_MD5).c_str(), _T(UNKNOWN_STRING), buffer, MAX_STR_BUFF, iniFileName); if(_tcscmp(buffer, _T(UNKNOWN_STRING))) file.m_md5 = CBase64::decodeBuffer(STRING(buffer).to_string().c_str()); TRACE_MESSAGE2("Rollback information read: '%s'", file.toString().c_str()); return true; }
void KLUPD::UpdateInfo::removeComponentFromUpdate( const ComponentIdentefiers componentsToRemove, // componentsToRemove - copy because when file is deleted iterator becomes invalid) JournalInterface &journal) { // removing component from retranslation filter for(ComponentIdentefiers::const_iterator iter = componentsToRemove.begin(); iter != componentsToRemove.end(); ++iter) { TRACE_MESSAGE2("Warning: removing components from update %S", iter->toWideChar()); // copy is needed, because iter will be invalid after remove from list const NoCaseString removingComponent = *iter; // removing from retranslation filter m_components.erase(std::remove_if(m_components.begin(), m_components.end(), std::bind2nd(std::equal_to<NoCaseString>(), removingComponent)), m_components.end()); m_componentsRemovedFromUpdate.push_back(removingComponent); journal.publishMessage ( m_retranslationMode ? EVENT_ComponentIsNotRetranslated : EVENT_ComponentIsNotUpdated, removingComponent ); } // removing file by component filter criteria if(!componentsToRemove.empty()) filterByComponents(componentsToRemove); }
KLUPD::CoreError KLUPD::AdministrationKitProtocol::setupLowLevelConnectionIfNeed(const bool useMasterAdministrationServer) { #ifdef DISABLE_AK_FILETRANSFER TRACE_MESSAGE("Administration Kit Transport is not implemented"); return CORE_DOWNLOAD_ERROR; #else if(m_connected) return CORE_NO_ERROR; m_downloadProgress.updateSpeedStartTimer(); KLFT::ConnectResult connectResult = KLFT::CR_ConnectionServerError; if(useMasterAdministrationServer) { TRACE_MESSAGE("Connecting to master administration server"); connectResult = m_adminKitTransprot->ConnectToMasterServer(); } else { TRACE_MESSAGE("Connecting to administration server"); connectResult = m_adminKitTransprot->Connect(); } m_downloadProgress.updateSpeedStopTimer(); switch(connectResult) { // successfully connected case KLFT::CR_Ok: m_connected = true; return CORE_NO_ERROR; // invalid AdminKit Transport identifier: either receiver was // deleted or connect was already called for this receiver case KLFT::CR_WrongReceiverId: return CORE_AK_WrongReceiverId; // AdminKit server is busy and can not handle requests now case KLFT::CR_ServerBusy: return CORE_AK_ServerBusy; // physical connection to AdminKit error case KLFT::CR_ConnectionError: return CORE_AK_ConnectionError; // connection to AdminKit network agent physical error case KLFT::CR_ConnectionNagentError: return CORE_AK_ConnectionNagentError; // connection to master AdminKit server physical error case KLFT::CR_ConnectionServerError: return CORE_AK_ConnectionServerError; // unknown AdminKit connection error default: TRACE_MESSAGE2("Connecting to Administration Server failed with unknown code '%d'", connectResult); return CORE_AK_CannotConnectToServer; } #endif // DISABLE_AK_FILETRANSFER }
bool KLUPD::UpdateInfo::checkIfFileOptional(const FileInfo absentFile) // absentFile is a copy, because update file set is modified { // in case component identifier is not specified, then it is primary index or other helper file for(ComponentIdentefiers::const_iterator componentIter = absentFile.m_componentIdSet.begin();; ++componentIter) { if(componentIter == absentFile.m_componentIdSet.end()) { TRACE_MESSAGE2("Error: component identifier is not specified '%S', file is mandatory and can not be removed from update", absentFile.toString().toWideChar()); return false; } // non-empty component found if(!componentIter->empty()) break; } // check if any of component's file is mandatory for(FileVector::const_iterator fileIter = m_matchFileList.begin(); fileIter != m_matchFileList.end(); ++fileIter) { // search if absent file has the same component identifier that absent file ComponentIdentefiers::const_iterator componentIter = std::find_first_of(absentFile.m_componentIdSet.begin(), absentFile.m_componentIdSet.end(), fileIter->m_componentIdSet.begin(), fileIter->m_componentIdSet.end()); // not match by component if(componentIter == absentFile.m_componentIdSet.end()) continue; if(!m_callbacks.checkIfFileOptional(*fileIter, m_retranslationMode)) { TRACE_MESSAGE3("Error: missing file '%S' which is mandatory for '%S'", absentFile.toString().toWideChar(), fileIter->toString().toWideChar()); return false; } } TRACE_MESSAGE2("File '%S' is optional for update", absentFile.toString().toWideChar()); return true; }
bool KLUPD::IniFile::save() { if(m_fileName.empty()) { TRACE_MESSAGE("Failed to save ini file, because no file name is specified"); return false; } FileStream file(pLog); if(!file.open(m_fileName, std::ios::out | std::ios::trunc)) { TRACE_MESSAGE2("Unable to save ini configuration file, because unable to open file '%S'", m_fileName.toWideChar()); return false; } for(std::vector<Section>::const_iterator sectionIter = m_sections.begin(); sectionIter != m_sections.end(); ++sectionIter) { bool wroteComment = false; if(!sectionIter->m_comment.empty()) { wroteComment = true; file.writeLine(NoCaseString(L"\n") + commentStr(sectionIter->m_comment)); } if(!sectionIter->m_name.empty()) { NoCaseString buffer = wroteComment ? L"\n" : L""; buffer += NoCaseString(L"[") + sectionIter->m_name + L"]"; file.writeLine(buffer); } for(std::vector<Key>::const_iterator keyIter = sectionIter->m_keys.begin(); keyIter != sectionIter->m_keys.end(); ++keyIter) { if(keyIter->m_key.empty()) continue; NoCaseString buffer = keyIter->m_comment.empty() ? L"" : L"\n"; buffer += commentStr(keyIter->m_comment); buffer += keyIter->m_comment.empty() ? L"" : L"\n"; buffer += keyIter->m_key.toWideChar(); buffer += s_equalIndicators[0]; buffer += keyIter->m_value; file.writeLine(buffer); } } m_dirty = false; return true; }
void KLUPD::UpdateInfo::filterByComponents(// filter parameter is passed *by value* const ComponentIdentefiers componentIdSet) { // filtering is not needed if(componentIdSet.empty()) return; for(size_t i = 0; i < m_matchFileList.size();) { // do not filter in case component is not set FileVector::iterator removeIter = m_matchFileList.begin(); std::advance(removeIter, i); // there is the only component with specified identifier in component set if(removeIter->m_componentIdSet.size() == 1) { // check if the only component in a set to remove if(std::find(componentIdSet.begin(), componentIdSet.end(), removeIter->m_componentIdSet[0]) != componentIdSet.end()) { TRACE_MESSAGE3("\tRemoved optional file from download list with Component Identifier '%S': %S", removeIter->m_componentIdSet[0].toWideChar(), removeIter->toString().toWideChar()); m_matchFileList.erase(removeIter); continue; } } // the file matches for several component else if(!removeIter->m_componentIdSet.empty()) { // removing all components in file component set for(ComponentIdentefiers::const_iterator iter = componentIdSet.begin(); iter != componentIdSet.end(); ++iter) { removeIter->m_componentIdSet.erase(std::remove_if(removeIter->m_componentIdSet.begin(), removeIter->m_componentIdSet.end(), std::bind2nd(std::equal_to<NoCaseString>(), *iter)), removeIter->m_componentIdSet.end()); } // no matched component rests, so removing file from list if(removeIter->m_componentIdSet.empty()) { TRACE_MESSAGE2("\tRemoved optional file from download list, because all its Component Identifiers are optional: %S", removeIter->toString().toWideChar()); m_matchFileList.erase(removeIter); continue; } } ++i; } }
bool KLUPD::NtlmImplementation::loadSecurityLibrary() { if(m_securityDll && m_funcionTable) return true; if(!m_securityDll) { m_securityDll = LoadLibrary(_T("secur32.dll")); if(!m_securityDll) { // on some platforms (e.g. Windows NT) there is no secur32.dll m_securityDll = LoadLibrary(_T("security.dll")); if(!m_securityDll) { const int lastError = GetLastError(); TRACE_MESSAGE2("Failed to load both 'secur32.dll' and 'security.dll' libraries, last error '%S'", errnoToString(lastError, windowsStyle).toWideChar()); return false; } } } PSecurityFunctionTable (*getFuncTable)(); getFuncTable = (PSecurityFunctionTable (*)(VOID))GetProcAddress(m_securityDll, tStringToAscii(SECURITY_ENTRYPOINT).c_str()); if(!getFuncTable) { const int lastError = GetLastError(); TRACE_MESSAGE3("Initialization NTLM functionality: failed to get function '%s' address, last error '%S'", tStringToAscii(SECURITY_ENTRYPOINT).c_str(), KLUPD::errnoToString(lastError, KLUPD::windowsStyle).toWideChar()); return false; } m_funcionTable = getFuncTable(); if(!m_funcionTable) { const int lastError = GetLastError(); TRACE_MESSAGE3("Initialization NTLM functionality: '%s' call failed, last error '%S'", tStringToAscii(SECURITY_ENTRYPOINT).c_str(), errnoToString(lastError, windowsStyle).toWideChar()); return false; } return true; }
static NTSTATUS InitWskBuffer_NBL( IN PNET_BUFFER_LIST NetBufferList, IN ULONG BufferOffset, OUT PWSK_BUF WskBuffer ) { NTSTATUS Status = STATUS_SUCCESS; TRACE_ENTER(); ASSERT(NetBufferList); ASSERT(WskBuffer); WskBuffer->Offset = BufferOffset; WskBuffer->Length = NetBufferList->FirstNetBuffer->DataLength - BufferOffset; WskBuffer->Mdl = NetBufferList->FirstNetBuffer->CurrentMdl; if (!WskBuffer->Mdl) { TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "InitWskBuffer_NBL()::NetBufferList->FirstNetBuffer->CurrentMdl failed with status 0x%08X\n", STATUS_INSUFFICIENT_RESOURCES); TRACE_EXIT(); return STATUS_INSUFFICIENT_RESOURCES; } __try { if ((WskBuffer->Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) != MDL_MAPPED_TO_SYSTEM_VA && (WskBuffer->Mdl->MdlFlags & MDL_PAGES_LOCKED) != MDL_PAGES_LOCKED && (WskBuffer->Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) != MDL_SOURCE_IS_NONPAGED_POOL) { MmProbeAndLockPages(WskBuffer->Mdl, KernelMode, IoWriteAccess); } } __except (EXCEPTION_EXECUTE_HANDLER) { TRACE_MESSAGE2(PACKET_DEBUG_LOUD, "InitWskBuffer_NBL()::MmProbeAndLockPages(%p) failed with status 0x%08X\n", WskBuffer->Mdl, STATUS_ACCESS_VIOLATION); Status = STATUS_ACCESS_VIOLATION; } TRACE_EXIT(); return Status; }
bool Ini_UpdaterLists::readRollbackFileListFromSS(FileVector &changedFiles) { const STRING section_name = SS_KEY_RollbackTree; STRING rollbackFileAndPath; if(!getProductFolder(m_useCurrentFolder, rollbackFileAndPath, pLog)) return false; rollbackFileAndPath += UPDATER_LISTS_FILENEME; TCHAR childSectionName[MAX_PATH + 1]; for(int _i = 0;; ++_i) { TCHAR szKeyName[MAX_PATH + 1]; TCHAR fullSectionName[MAX_PATH + MAX_PATH + 1]; memset(childSectionName, 0, (MAX_PATH + 1) * sizeof(TCHAR)); memset(szKeyName, 0, (MAX_PATH + 1) * sizeof(TCHAR)); memset(fullSectionName, 0, (MAX_PATH + MAX_PATH + 1) * sizeof(TCHAR)); _stprintf(szKeyName, _T("entry%d"), _i); GetPrivateProfileString(section_name.c_str(), szKeyName, _T(""), childSectionName, MAX_PATH, rollbackFileAndPath.c_str()); if(!childSectionName[0]) break; _tcscpy(fullSectionName, section_name.c_str()); _tcscat(fullSectionName, _T(":")); _tcscat(fullSectionName, childSectionName); FileInfo rec; if(!readSingleFileInfoRollback(rollbackFileAndPath.c_str(), fullSectionName, rec)) { TRACE_MESSAGE2("Invalid content of '%s' section, skipping", fullSectionName); // ignore error, try next entry if any continue; } changedFiles.push_back(rec); } return true; }
KLUPD::CoreError HttpTransport::dataReceived(const unsigned char *data, const size_t &size) { if(!m_destinationIO) { TRACE_MESSAGE("Warning: unable to write received data, no destination file is specified'"); return KLUPD::CORE_NO_ERROR; } const tERROR writeFileResult = m_destinationIO->SeekWrite(0, m_currentOffset, const_cast<void *>(reinterpret_cast<const void *>(data)), size); if(PR_SUCC(writeFileResult)) { m_currentOffset += size; return KLUPD::CORE_NO_ERROR; } TRACE_MESSAGE2("Failed to write received data with result '%s'", PRAGUE_HELPERS::toStringPragueResult(writeFileResult).c_str()); return KLUPD::CORE_GenericFileOperationFailure; }
bool KLUPD::IniFile::load() { if(!LocalFile(m_fileName, pLog).exists()) { TRACE_MESSAGE2("File does not exist '%S'", m_fileName.toWideChar()); return false; } // do not create a new file here. If it doesn't exist, just return false and report the failure. FileStream file(pLog); if(!file.open(m_fileName, std::ios::in)) { TRACE_MESSAGE2("Failed to load ini configuration file, because failed to open file '%S'", m_fileName.toWideChar()); return false; } const bool autoKey = (m_flags & AUTOCREATE_KEYS) == AUTOCREATE_KEYS; const bool autoSec = (m_flags & AUTOCREATE_SECTIONS) == AUTOCREATE_SECTIONS; NoCaseString comment; Section *section = getSection(L""); // needs to be set to restore the original values later m_flags |= AUTOCREATE_KEYS | AUTOCREATE_SECTIONS; bool doneWithFile = false; while(!doneWithFile) { NoCaseString line; file.getLine(line); line.trim(); doneWithFile = file.done(); if(line.find_first_of(s_commentIndicators.toWideChar()) == 0) { comment += L"\n"; comment += line; } // new section else if(line.find_first_of("[") == 0) { line.erase(0, 1); const size_t lastOffset = line.find_last_of("]"); if(lastOffset != NoCaseStringImplementation::npos) { line.erase(lastOffset, 1); createSection(line, comment); section = getSection(line); comment = NoCaseString(); } } // we have a key, add this key/value pair else if(!line.empty()) { NoCaseString keyName = getNextWord(line); NoCaseString value = line; if(!keyName.empty()) { setValue(keyName, value, section ? section->m_name : NoCaseString(), comment); comment = NoCaseString(L""); } } } // restore the original flag values. if(!autoKey) m_flags &= ~AUTOCREATE_KEYS; if(!autoSec) m_flags &= ~AUTOCREATE_SECTIONS; return true; }
NTSTATUS NPF_Open(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PDEVICE_EXTENSION DeviceExtension; POPEN_INSTANCE Open; PIO_STACK_LOCATION IrpSp; NDIS_STATUS Status; NDIS_STATUS ErrorStatus; UINT i; PUCHAR tpointer; PLIST_ENTRY PacketListEntry; NTSTATUS returnStatus; // // Old registry based WinPcap names // // WCHAR EventPrefix[MAX_WINPCAP_KEY_CHARS]; // UINT RegStrLen; TRACE_ENTER(); DeviceExtension = DeviceObject->DeviceExtension; IrpSp = IoGetCurrentIrpStackLocation(Irp); // allocate some memory for the open structure Open=ExAllocatePoolWithTag(NonPagedPool, sizeof(OPEN_INSTANCE), '0OWA'); if (Open==NULL) { // no memory Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory( Open, sizeof(OPEN_INSTANCE) ); // // Old registry based WinPcap names // // // // // Get the Event names base from the registry // // // RegStrLen = sizeof(EventPrefix)/sizeof(EventPrefix[0]); // // NPF_QueryWinpcapRegistryString(NPF_EVENTS_NAMES_REG_KEY_WC, // EventPrefix, // RegStrLen, // NPF_EVENTS_NAMES_WIDECHAR); // Open->DeviceExtension=DeviceExtension; // Allocate a packet pool for our xmit and receive packets NdisAllocatePacketPool( &Status, &Open->PacketPool, TRANSMIT_PACKETS, sizeof(PACKET_RESERVED)); if (Status != NDIS_STATUS_SUCCESS) { TRACE_MESSAGE(PACKET_DEBUG_LOUD, "Failed to allocate packet pool"); ExFreePool(Open); Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INSUFFICIENT_RESOURCES; } NdisInitializeEvent(&Open->WriteEvent); NdisInitializeEvent(&Open->NdisRequestEvent); NdisInitializeEvent(&Open->NdisWriteCompleteEvent); NdisInitializeEvent(&Open->DumpEvent); NdisAllocateSpinLock(&Open->MachineLock); NdisAllocateSpinLock(&Open->WriteLock); Open->WriteInProgress = FALSE; for (i = 0; i < g_NCpu; i++) { NdisAllocateSpinLock(&Open->CpuData[i].BufferLock); } NdisInitializeEvent(&Open->NdisOpenCloseCompleteEvent); // list to hold irp's want to reset the adapter InitializeListHead(&Open->ResetIrpList); // Initialize the request list KeInitializeSpinLock(&Open->RequestSpinLock); InitializeListHead(&Open->RequestList); #ifdef HAVE_BUGGY_TME_SUPPORT // Initializes the extended memory of the NPF machine Open->mem_ex.buffer = ExAllocatePoolWithTag(NonPagedPool, DEFAULT_MEM_EX_SIZE, '2OWA'); if((Open->mem_ex.buffer) == NULL) { // // no memory // ExFreePool(Open); Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_INSUFFICIENT_RESOURCES; } Open->mem_ex.size = DEFAULT_MEM_EX_SIZE; RtlZeroMemory(Open->mem_ex.buffer, DEFAULT_MEM_EX_SIZE); #endif //HAVE_BUGGY_TME_SUPPORT // // Initialize the open instance // Open->bpfprogram = NULL; //reset the filter Open->mode = MODE_CAPT; Open->Nbytes.QuadPart = 0; Open->Npackets.QuadPart = 0; Open->Nwrites = 1; Open->Multiple_Write_Counter = 0; Open->MinToCopy = 0; Open->TimeOut.QuadPart = (LONGLONG)1; Open->DumpFileName.Buffer = NULL; Open->DumpFileHandle = NULL; #ifdef HAVE_BUGGY_TME_SUPPORT Open->tme.active = TME_NONE_ACTIVE; #endif // HAVE_BUGGY_TME_SUPPORT Open->DumpLimitReached = FALSE; Open->MaxFrameSize = 0; Open->WriterSN=0; Open->ReaderSN=0; Open->Size=0; Open->SkipSentPackets = FALSE; Open->ReadEvent = NULL; // // we need to keep a counter of the pending IRPs // so that when the IRP_MJ_CLEANUP dispatcher gets called, // we can wait for those IRPs to be completed // Open->NumPendingIrps = 0; Open->ClosePending = FALSE; NdisAllocateSpinLock(&Open->OpenInUseLock); // //allocate the spinlock for the statistic counters // NdisAllocateSpinLock(&Open->CountersLock); // // link up the request stored in our open block // for (i = 0 ; i < MAX_REQUESTS ; i++ ) { NdisInitializeEvent(&Open->Requests[i].InternalRequestCompletedEvent); ExInterlockedInsertTailList( &Open->RequestList, &Open->Requests[i].ListElement, &Open->RequestSpinLock); } NdisResetEvent(&Open->NdisOpenCloseCompleteEvent); // // set the proper binding flags before trying to open the MAC // Open->AdapterBindingStatus = ADAPTER_BOUND; Open->AdapterHandleUsageCounter = 0; NdisAllocateSpinLock(&Open->AdapterHandleLock); // // Try to open the MAC // TRACE_MESSAGE2(PACKET_DEBUG_LOUD,"Opening the device %ws, BindingContext=%p",DeviceExtension->AdapterName.Buffer, Open); returnStatus = STATUS_SUCCESS; NdisOpenAdapter( &Status, &ErrorStatus, &Open->AdapterHandle, &Open->Medium, MediumArray, NUM_NDIS_MEDIA, g_NdisProtocolHandle, Open, &DeviceExtension->AdapterName, 0, NULL); TRACE_MESSAGE1(PACKET_DEBUG_LOUD,"Opened the device, Status=%x",Status); if (Status == NDIS_STATUS_PENDING) { NdisWaitEvent(&Open->NdisOpenCloseCompleteEvent, 0); if (!NT_SUCCESS(Open->OpenCloseStatus)) { returnStatus = Open->OpenCloseStatus; } else { returnStatus = STATUS_SUCCESS; } } else { // // request not pending, we know the result, and OpenComplete has not been called. // if (Status == NDIS_STATUS_SUCCESS) { returnStatus = STATUS_SUCCESS; } else { // // this is not completely correct, as we are converting an NDIS_STATUS to a NTSTATUS // returnStatus = Status; } } if (returnStatus == STATUS_SUCCESS) { ULONG localNumOpenedInstances; // // complete the open // localNumOpenedInstances = InterlockedIncrement(&g_NumOpenedInstances); TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Opened Instances: %u", localNumOpenedInstances); // Get the absolute value of the system boot time. // This is used for timestamp conversion. TIME_SYNCHRONIZE(&G_Start_Time); returnStatus = NPF_GetDeviceMTU(Open, Irp, &Open->MaxFrameSize); if (!NT_SUCCESS(returnStatus)) { // // Close the binding // NPF_CloseBinding(Open); } } if (!NT_SUCCESS(returnStatus)) { NPF_ReleaseOpenInstanceResources(Open); // // Free the open instance itself // ExFreePool(Open); } else { // Save or open here IrpSp->FileObject->FsContext=Open; } Irp->IoStatus.Status = returnStatus; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); TRACE_EXIT(); return returnStatus; }
bool KLUPD::HttpProtocol::switchAuthorization(const Path &fileName, const Path &relativeUrlPath, const DownloadProgress::AuthorizationTarget &authorizationTarget, const Address &proxyAddress, bool &authorizationTypeSwitched, bool &ntlmAuthorizationTriedAlready) { authorizationTypeSwitched = false; const AuthorizationType currentAuthorizationType = m_authorizationDriver.currentAuthorizationType(); if(!m_downloadProgress.authorizationTargetEnabled(authorizationTarget)) { TRACE_MESSAGE2("Failed to switch authorization by product '%s'", DownloadProgress::toString(authorizationTarget).c_str()); return false; } // authorization needed bool needUpdateCredentials = false; const bool switchedToNextAuthorizationSuccess = m_authorizationDriver.switchToNextAuthorization(needUpdateCredentials, ntlmAuthorizationTriedAlready); // report authorization failed if(!switchedToNextAuthorizationSuccess || needUpdateCredentials) { if(m_authorizationDriver.credentials().userName().empty()) informAuthorizationFailed(authorizationTarget, relativeUrlPath + fileName, proxyAddress.BuildURI().toWideChar()); else { informAuthorizationFailed(authorizationTarget, relativeUrlPath + fileName, m_authorizationDriver.credentials().userName() + L"@" + proxyAddress.BuildURI().toWideChar()); } } if(!switchedToNextAuthorizationSuccess) return false; if(needUpdateCredentials) { Credentials newCredentials = m_authorizationDriver.credentials(); // proxy authorization failed, asking credentials to authenticate on proxy if(!m_downloadProgress.requestAuthorizationCredentials(newCredentials)) { TRACE_MESSAGE("User cancelled HTTP authorization"); // Treat cancel as "don't use credentials at all" //m_authorizationDriver.resetNtlmState(); newCredentials.cancel( true ); m_authorizationDriver.credentials( newCredentials ); m_authorizationDriver.currentAuthorizationType(noAuthorization); // reset authorization to initial state to keep object consistency bool needUpdateCredentials = false; bool ntlmAuthorizationTriedAlready = false; m_authorizationDriver.switchToNextAuthorization(needUpdateCredentials, ntlmAuthorizationTriedAlready); return false; } // no credentials specified if(newCredentials.userName().empty()) { TRACE_MESSAGE("Credentials to authenticate on proxy were asked, but not obtained from Product: user name is empty"); return false; } TRACE_MESSAGE2("Credentials to authenticate on proxy were asked, user name provided is '%S'", newCredentials.userName().toWideChar()); m_authorizationDriver.credentials(newCredentials); } authorizationTypeSwitched = currentAuthorizationType != m_authorizationDriver.currentAuthorizationType(); return true; }
bool Ini_UpdaterLists::processChangedFiles(const STRING &rollbackFolder, const bool validLocalFilesForRollback) { // Ini updater can not perform rollback in retranslation mode if(m_retranslation) return false; if(!validLocalFilesForRollback) { TRACE_MESSAGE("Rollback is not created, because inconsistent bases set was locally before update operation started"); removeRollbackSection(); return false; } TRACE_MESSAGE("Saving rollback file list"); FileVector updateList; // set correct status for all entries that have changed std::string rollbackTrace; for(size_t index = 0; index < m_changedFiles.size(); ++index) { // entry copy, because size, signature, and hash tags are not valid here. // There are values not for rollback, but values for new files FileInfo entryCopy; entryCopy.m_filename = m_changedFiles[index].m_filename; entryCopy.m_localPath = m_changedFiles[index].m_localPath; entryCopy.m_rollbackChange; switch(m_changedFiles[index].m_transactionInformation.m_changeStatus) { case FileInfo::added: entryCopy.m_rollbackChange = SS_KEY_RecentStatusAdded; break; case FileInfo::deleted: entryCopy.m_rollbackChange = SS_KEY_RecentStatusDeleted; break; case FileInfo::modified: entryCopy.m_rollbackChange = SS_KEY_RecentStatusModified; break; default: // do not write to rollback settings storage unchanged files continue; } // calculate MD5 for consistency check to restore changed and deleted files if((entryCopy.m_rollbackChange != SS_KEY_RecentStatusAdded) && !calcMD5Hash(STRING(rollbackFolder + entryCopy.m_filename).to_string().c_str(), entryCopy.m_md5)) { TRACE_MESSAGE2("Rollback is not created, failed to calculate md5 for '%s'", (rollbackFolder + entryCopy.m_filename).to_string().c_str()); return false; } updateList.push_back(entryCopy); if(index != 0) rollbackTrace += ", "; if(!(index % 15)) rollbackTrace += "\n\t"; rollbackTrace += entryCopy.m_filename.to_string() + " " + entryCopy.m_rollbackChange.to_string().c_str(); } TRACE_MESSAGE2("Saving rollback files: %s", rollbackTrace.c_str()); // saving rollback information if(!saveRollbackInfo(updateList)) { TRACE_MESSAGE("Failed to save rollback file list"); return false; } TRACE_MESSAGE("Rollback file list saved successfully"); return true; }
KLUPD::CoreError KLUPD::AdministrationKitProtocol::getFile( const Path &fileName, const Path &localPath, const Path &relativeUrlPathIn, const bool useMasterAdministrationServer) { #ifdef DISABLE_AK_FILETRANSFER TRACE_MESSAGE("Administration Kit Transport is not implemented"); return CORE_DOWNLOAD_ERROR; #else // skip initial slash in relative URL path Path relativeUrlPath = relativeUrlPathIn; if(!relativeUrlPath.empty() && (relativeUrlPath[0] == L'\\' || relativeUrlPath[0] == L'/')) { relativeUrlPath = relativeUrlPath.toWideChar() + 1; } const Path path = relativeUrlPath + fileName; /////////////////////////////////////////////// /// checking current state and parameters const CoreError connectionResult = setupLowLevelConnectionIfNeed(useMasterAdministrationServer); if(connectionResult != CORE_NO_ERROR) { TRACE_MESSAGE2("Failed to setup connection to Administration Server, result '%S'", toString(connectionResult).toWideChar()); return connectionResult; } /////////////////////////////////////////////// /// receiving data by portions size_t regettingPosition = LocalFile(localPath + fileName).size(); AutoStream destinationFile(pLog); while(true) { // check if request should be cancelled if(m_downloadProgress.checkCancel()) { TRACE_MESSAGE2("File transfer cancelled '%S'", path.toWideChar()); return CORE_CANCELLED; } const long localBufferSize = 65536; std::vector<unsigned char> localBuffer(localBufferSize, 0); int bytesRead = 0; m_downloadProgress.updateSpeedStartTimer(); const KLFT::FileOpeartionResult getChunkResult = m_adminKitTransprot->GetFileChunk( path.toWideChar(), regettingPosition, &localBuffer[0], localBuffer.size(), bytesRead); m_downloadProgress.updateSpeedStopTimer(); // a portion of file got successfully if(getChunkResult == KLFT::FR_Ok || getChunkResult == KLFT::FR_OkDownloaded) { const CoreError saveDataToFileResult = saveDataToFile( localPath + fileName, &localBuffer[0], bytesRead, regettingPosition != 0, destinationFile, pLog); if(!isSuccess(saveDataToFileResult)) { TRACE_MESSAGE3("Failed to write data obtained from Administration Server to file '%S', result '%S'", path.toWideChar(), toString(saveDataToFileResult).toWideChar()); return saveDataToFileResult; } regettingPosition += bytesRead; m_downloadProgress.bytesTransferred(bytesRead); // file has been completely downloaded if(getChunkResult == KLFT::FR_OkDownloaded) return CORE_NO_ERROR; continue; } TRACE_MESSAGE5("Failed to obtain file chunk from Administration Server, file '%S', result '%s', bytes read %d, current position %d", path.toWideChar(), toString(getChunkResult).c_str(), bytesRead, regettingPosition); if(getChunkResult == KLFT::FR_Timeout) { // TODO check if time out is over and error should be returned continue; } // error while download happened switch(getChunkResult) { // invalid AdminKit Transport identifier: either receiver was deleted or connect was already called for this receiver case KLFT::FR_WrongReceiverId: return CORE_AK_WrongReceiverId; // invalid arguments for AdminKit Transport // wrong offset is requested, consider file is downloaded and signature should be checked case KLFT::FR_WrongArguments: { // TODO: this is *work around* about the problem that AdminKit returns return CORE_NO_ERROR; // FR_WrongArguments code in case source contains // valid file in target download folder // this code can be deleted when problem is fixed in AdminKit } // file not found on AdminKit server case KLFT::FR_FileNotFound: return CORE_NO_SOURCE_FILE; // AdminKit transport file receive error case KLFT::FR_ErrorInOperation: return CORE_AK_ErrorInOperation; // unknown AdminKit transport receive operation error default: return CORE_AK_UnknownError; } } #endif // DISABLE_AK_FILETRANSFER }
KLUPD::CoreError KLUPD::HttpProtocol::httpRequestAttempt( const Path &fileNameIn, const Path &relativeUrlPathIn, const Address &serverAddressIn, const std::string &userAgent, const bool useProxy, const Address &proxyAddressIn, const AuthorizationTypeList &proxyAuthorizationMethods, const size_t regettingPosition) { size_t infiniteRedirectLoop = 0; Path fileName = fileNameIn; Path relativeUrlPath = relativeUrlPathIn; Address serverAddress = serverAddressIn; Address proxyAddress = proxyAddressIn; m_regettingPosition = regettingPosition; // cache for next iteration generate request // at first attempt the target is not known, but proxy server target is used, // because of possible protection from client for authorization on server DownloadProgress::AuthorizationTarget authorizationTarget = DownloadProgress::proxyServer; //////////////////// // the State flags agains proxies that close connection after authorization switch. // There are proxies (e.g. Squid/2.4.STABLE7) which deals in next way: // *** Client -> Server: GET file // *** Server -> Client: HTTP 407 / Proxy-Connection: keep-alive // *** Server closes connection // *** Client -> Server GET 407 // // Here are 3 flags to track such situations, that previous response is received, // BUT then server closes connection bool previousResponseReceived = false; bool authorizationTypeSwitched = false; bool requestHasAlreadyBeenRepeated = false; //////////////////// //////////////////// // in case proxy server requires authorization, but sends incorrect (from HTTP) // code for authorization failure in next way // *** Client -> Server: GET file // *** Server -> Client: HTTP 407 / Proxy-Authorization: NTLM // *** Client -> Server GET / Proxy-Authorization: NTLM // *** Server -> Client: HTTP 502 (or 403 or other code) // *** here is authorization state is forgotten, because 502 request does NOT contain "Proxy-Authorization: NTLM" // *** Client ask from product new credentials // *** Client -> Server GET / Proxy-Authorization: NTLM (with new credentials) bool authorizationWasNeededOnProxy = false; // it makes no sence to try Ntlm without credentials authorization type, // because this authorization type does not depend on provided credentials bool ntlmAuthorizationTriedAlready = false; int lastHttpCode = 0; for(size_t protectionAgainstCyclingCounter = 100; protectionAgainstCyclingCounter; --protectionAgainstCyclingCounter) { const CoreError connectionResult = setupLowLevelConnectionIfNeed(useProxy, useProxy ? proxyAddress : serverAddress, proxyAuthorizationMethods); if(connectionResult != CORE_NO_ERROR) { TRACE_MESSAGE2("Failed to setup connection to HTTP Server, result '%S'", toString(connectionResult).toWideChar()); return connectionResult; } // make proxy authorization header std::string proxyAuthorizationHeader; if(!m_authorizationDriver.makeProxyAuthorizationHeader(proxyAuthorizationHeader) // we know authorization methods supported by proxy server || ((m_authorizationDriver.currentAuthorizationType() == noAuthorization) && !m_authorizationDriver.supportedAuthorizationTypesByServer().empty())) { if(!switchAuthorization(fileName, relativeUrlPath, authorizationTarget, proxyAddress, authorizationTypeSwitched, ntlmAuthorizationTriedAlready)) { if(lastHttpCode) return HttpHeader::convertHttpCodeToUpdaterCode(lastHttpCode); return useProxy ? CORE_PROXY_AUTH_ERROR : CORE_SERVER_AUTH_ERROR; } // try other authorization type continue; } HTTPRequestBuilder requestBuilder(m_method); const std::vector<unsigned char> requestBuffer = requestBuilder.generateRequest( fileName, relativeUrlPath, useProxy, serverAddress, userAgent, proxyAuthorizationHeader, m_regettingPosition, m_postData); TRACE_MESSAGE2("Sending HTTP request\n%s", requestBuilder.toString().c_str()); if(requestBuffer.empty()) { TRACE_MESSAGE("Failed to send empty HTTP request"); return CORE_DOWNLOAD_ERROR; } const CoreError sendRequestResult = m_socket.send(reinterpret_cast<const char *>(&requestBuffer[0]), requestBuffer.size()); if(sendRequestResult != CORE_NO_ERROR) { TRACE_MESSAGE2("Failed to send HTTP request, error %S", toString(sendRequestResult).toWideChar()); if((sendRequestResult == CORE_REMOTE_HOST_CLOSED_CONNECTION) && previousResponseReceived && authorizationTypeSwitched && !requestHasAlreadyBeenRepeated) { TRACE_MESSAGE("Repeating the same request (without authorization switch), because server was reachable, but unexpectedly closed connection"); requestHasAlreadyBeenRepeated = true; continue; } return sendRequestResult; } HttpHeader httpHeader; const CoreError receiveResponseAndDataResult = receiveResponseAndData(httpHeader); const bool needCloseConnection = httpHeader.needCloseConnection(useProxy) || (receiveResponseAndDataResult != CORE_NO_ERROR); if(needCloseConnection) { TRACE_MESSAGE2("Closing connection to HTTP server, get file result %S", toString(receiveResponseAndDataResult).toWideChar()); closeSession(); } if(receiveResponseAndDataResult != CORE_NO_ERROR) { TRACE_MESSAGE2("Failed to receive HTTP response, error %S", toString(receiveResponseAndDataResult).toWideChar()); if((receiveResponseAndDataResult == CORE_REMOTE_HOST_CLOSED_CONNECTION) && previousResponseReceived && authorizationTypeSwitched && !requestHasAlreadyBeenRepeated) { TRACE_MESSAGE("Repeating the same request (without authorization switch), because server was reachable, but unexpectedly closed connection"); requestHasAlreadyBeenRepeated = true; continue; } return receiveResponseAndDataResult; } previousResponseReceived = true; requestHasAlreadyBeenRepeated = false; m_authorizationDriver.authorized( // authorization information is reset in case connection is to be closed !needCloseConnection // authorization success in case file received or successful redirect && (httpHeader.isFile() || httpHeader.redirectRequired() || httpHeader.fileNotFound())); if(httpHeader.isFile()) { // in case proxy server by some ocassion desided to close // connection after successful file receive event if(needCloseConnection) m_authorizationDriver.resetNtlmState(); return CORE_NO_ERROR; } authorizationTarget = httpHeader.authorizationTarget(); authorizationWasNeededOnProxy = !proxyAuthorizationHeader.empty(); lastHttpCode = httpHeader.httpCode(); // authorization error if(httpHeader.authorizationNeeded()) { authorizationWasNeededOnProxy = (authorizationTarget == DownloadProgress::proxyServer); if(!switchAuthorization(fileName, relativeUrlPath, httpHeader.authorizationTarget(), proxyAddress, authorizationTypeSwitched, ntlmAuthorizationTriedAlready)) { return httpHeader.convertHttpCodeToUpdaterCode(); } } // redirect needed else if(httpHeader.redirectRequired()) { // protection against infinite loop (according to RFC 2616) if(++infiniteRedirectLoop > 2) { TRACE_MESSAGE2("Infinite redirection loop detected for location '%S'", httpHeader.m_location.toWideChar()); return CORE_NO_SOURCE_FILE; } if(httpHeader.m_location.isAbsoluteUri()) serverAddress.parse(httpHeader.m_location); else { serverAddress.parse(toProtocolPrefix(serverAddress.m_protocol) + serverAddress.m_hostname + serverAddress.m_path + httpHeader.m_location); serverAddress.m_path.correctPathDelimiters(); } fileName = serverAddress.m_fileName; relativeUrlPath.erase(); TRACE_MESSAGE3("HTTP Redirect to file '%S' on server %S", fileName.toWideChar(), serverAddress.toString().toWideChar()); } // known HTTP results else if(httpHeader.resourceUnavailable() || httpHeader.fileNotFound()) { return httpHeader.convertHttpCodeToUpdaterCode(); } // retry authorization with other credentials in case Forbidden // code received after successful authorization has happened else if(httpHeader.retryAuthorization(authorizationWasNeededOnProxy) && treat_403_502_httpCodesAs407()) { if(!switchAuthorization(fileName, relativeUrlPath, DownloadProgress::proxyServer, proxyAddress, authorizationTypeSwitched, ntlmAuthorizationTriedAlready)) { TRACE_MESSAGE2("Authorization was needed, but error HTTP code '%d' received and switch to next authorization type failed", httpHeader.httpCode()); return httpHeader.convertHttpCodeToUpdaterCode(); } TRACE_MESSAGE3("Authorization was needed, but error HTTP code '%d' received, try next authorization type '%S'", httpHeader.httpCode(), toString(m_authorizationDriver.currentAuthorizationType()).toWideChar()); } else { // processing HTTP code is not implemented m_authorizationDriver.resetAuthorizatoinState(proxyAuthorizationMethods); return httpHeader.convertHttpCodeToUpdaterCode(); } } // Authorization state machine is complex and may contain bug, // that is why protection against infinite loop is implemented TRACE_MESSAGE3("Error in HTTP authorization state implementation: credentials '%S', current authorization type '%S'", m_authorizationDriver.credentials().toString().toWideChar(), toString(m_authorizationDriver.currentAuthorizationType()).toWideChar()); return CORE_DOWNLOAD_ERROR; }
KLUPD::CoreError KLUPD::HttpProtocol::receiveResponseAndData(HttpHeader &httpHeader) { bool httpHeaderFullyReceived = false; const char *entity = 0; size_t total_entity_bytes = 0; const size_t httpBufferSize = 65536; char httpBuffer[httpBufferSize + 1]; memset(httpBuffer, 0, httpBufferSize + 1); size_t currentOffsetInHttpBuffer = 0; while(true) { CoreError receiveResult = CORE_NO_ERROR; const int bytesReceived = m_socket.recv(httpBuffer + currentOffsetInHttpBuffer, httpBufferSize - currentOffsetInHttpBuffer, receiveResult); currentOffsetInHttpBuffer += bytesReceived; // according to RFC 2616, 4.4 point 5: connection close may indicate // file transfer completion if Range or Content-Length is not specified if(httpHeaderFullyReceived && (receiveResult == CORE_REMOTE_HOST_CLOSED_CONNECTION) && (httpHeader.m_contentLength == -1)) { TRACE_MESSAGE2("HTTP connection closed by server, no Content-Length field, consider file is obtained, size %d bytes", currentOffsetInHttpBuffer); return CORE_NO_ERROR; } if(receiveResult != CORE_NO_ERROR) return receiveResult; // size of entity part that is currently in buffer size_t entityBytes = 0; if(httpHeaderFullyReceived) { // http header was obtained on previous iteration entityBytes = currentOffsetInHttpBuffer; entity = httpBuffer; } else { // HTTP header has not been obtained yet, check if it is in httpBuffer const char *const headerEndMarker = "\r\n\r\n"; char *const headerLastPosition = strstr(httpBuffer, headerEndMarker); if(!headerLastPosition) { // no end-of-header marker found if(httpBufferSize < currentOffsetInHttpBuffer) { TRACE_MESSAGE3("Error: response HTTP header can not fit into %d-bytes buffer (already received %d bytes)", httpBufferSize, currentOffsetInHttpBuffer); return CORE_DOWNLOAD_ERROR; } // continue reading from socket continue; } httpHeaderFullyReceived = true; // pass to applicaiton data included into HTTP header fullHttpHeaderReceived(std::string(httpBuffer, headerLastPosition + strlen(headerEndMarker))); *headerLastPosition = 0; TRACE_MESSAGE2("HTTP response received:\n%s", HTTPRequestBuilder::toString(httpBuffer).c_str()); // Parse HTTP header, data loaded into httpHeader structure if(!httpHeader.load(httpBuffer, m_authorizationDriver)) { TRACE_MESSAGE("Failed to parse HTTP response header"); return CORE_DOWNLOAD_ERROR; } // it is expected 206 code in case regetting is used if(m_regettingPosition && (httpHeader.httpCode() == 200)) { TRACE_MESSAGE("It is expected 206 code in case regetting is used, but 200 code is received"); return CORE_DOWNLOAD_ERROR; } // data from socket after the HTTP header entityBytes = (httpBuffer + currentOffsetInHttpBuffer) // pointer to the end of received bytes - (headerLastPosition + strlen(headerEndMarker)); // pointer to the data (begin of the file) entity = entityBytes ? headerLastPosition + strlen(headerEndMarker) : 0; } total_entity_bytes += entityBytes; if(httpHeader.isFile() // only header has been received, but data is not received yet && entityBytes) { const CoreError saveDataToFileResult = dataReceived(reinterpret_cast<const unsigned char *>(entity), entityBytes); if(!isSuccess(saveDataToFileResult)) { TRACE_MESSAGE2("Failed to write data obtained from HTTP Server, result %S", toString(saveDataToFileResult).toWideChar()); return saveDataToFileResult; } m_regettingPosition += entityBytes; } ////////////////////////////////////////////////////////////////////////// /// check if complete file is downloaded // Content-Length header presents if(httpHeader.m_contentLength == -1) { TRACE_MESSAGE("HTTP chunk received (header does not contain the content-length field), continue receiving message until connection is closed by remote peer"); } else if(static_cast<size_t>(httpHeader.m_contentLength) <= total_entity_bytes) { TRACE_MESSAGE2("HTTP message successfully received, content length = %d", httpHeader.m_contentLength); return CORE_NO_ERROR; } currentOffsetInHttpBuffer = 0; entityBytes = 0; } }
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; }