//------------------------------------------------------------------------------ void DirectoryComparer::copy () { // variables FileCopier copier(safe_mode); FileVector& f0 = _uc[0].f; // for convenience vector<path>& d0 = _uc[0].d; // for convenience path fullpath0; // convenience (updated in loops) path fullpath1; // convenience (updated in loops) FileVector errors; // holds files that we fail to copy // precompute total number of files and bytes to be transferred annotate0(); // prepare batch, print totals unsigned totalFiles = _uc[0].files(); FileSize totalBytes = _uc[0].bytes(); copier.startBatch(totalFiles, totalBytes); cout << "========== Copying Files from A to B ==========\n"; cout << "Copying " << totalFiles << " files totaling " << totalBytes << " from " << workingPath(0) << " to " << workingPath(1) << ".\n"; cout << " Bytes Processed | Current File\n"; // copy files from _uc[0].f for (unsigned i=0; i<f0.size(); ++i) { fullpath0 = groundPath(f0[i], 0); fullpath1 = groundPath(f0[i], 1); if (exists(fullpath1)) { // error! errors.push_back(f0[i], fullpath0); cout << "Warning: Cannot copy " << fullpath0 << " to " << fullpath1 << " because the latter already exists.\n"; } else { copier.copy(fullpath0, fullpath1, f0[i]); } } // copy files from _uc[0].d recursive_directory_iterator end; unsigned depth = 0; path connector; path new_extension; for (unsigned i=0; i<d0.size(); ++i) { // initialize for recursive crawl of this directory recursive_directory_iterator itr(groundPath(d0[i], 0)); depth = 0; connector = d0[i]; cout << copier.status << "Creating directory " << connector << '.' << '\n'; if (!safe_mode) create_directory(_p[1] / connector); while (itr != end) { // update connector if (depth < itr.level()) { connector /= new_extension; cout << copier.status << "Creating directory " << connector << '.' << '\n'; if (!safe_mode) create_directory(_p[1] / connector); ++depth; // this makes depth equal to itr.level() } else while (depth > itr.level()) { connector.remove_filename(); --depth; } // copy file or save name of directory we may iterate into if (is_regular_file(itr->path())) { fullpath0 = itr->path(); fullpath1 = _p[1] / connector / fullpath0.filename(); if (exists(fullpath1)) { // error! errors.push_back(connector / fullpath0.filename(), fullpath0); cout << copier.status << "Warning: Cannot copy " << fullpath0 << " to " << fullpath1 << " because the latter already exists.\n"; } else { copier.copy(fullpath0, fullpath1, connector / fullpath0.filename()); } } else if (is_directory(itr->path())) { new_extension = itr->path().filename(); } ++itr; } } // cleanup _uc[0].f.clear(); _uc[0].d.clear(); _annotations &= ~A0; // print outline cout << setw(9) << totalBytes << '/' << setw(9) << totalBytes << " | "; cout << totalFiles - errors.size() << " of " << totalFiles << " files were copied.\n"; if (errors.size()) { cout << "The following files were not copied:\n"; for (unsigned i=0; i<errors.size(); ++i) { cout << errors[i] << '\n'; } } cout << '\n'; }
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; }