From: hama Date: Sat, 30 Jan 2016 02:04:06 +0000 (+0100) Subject: rebackgui works X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=8a603a3a0e1ccd5ca014f93de719af6a7e7c2f8b;p=reqt rebackgui works --- diff --git a/appl/rebackgui/BackupEngine.cpp b/appl/rebackgui/BackupEngine.cpp index 3950da9..025c0a4 100644 --- a/appl/rebackgui/BackupEngine.cpp +++ b/appl/rebackgui/BackupEngine.cpp @@ -10,8 +10,11 @@ bool BackupEngine::m_shouldStop = false; QStringList BackupEngine::m_files; -qint64 BackupEngine::m_matchedBytes = 0; +qint64 BackupEngine::m_hotBytes = 0; +qint64 BackupEngine::m_processedBytes = 0; +int BackupEngine::m_processedFiles = 0; int BackupEngine::m_matchedFiles = 0; +int BackupEngine::m_hotFiles = 0; int BackupEngine::m_totalFiles = 0; int BackupEngine::m_totalDirs = 0; bool BackupEngine::m_searchReady = false; @@ -100,16 +103,22 @@ void SearchTask::run() { qint64 start = QDateTime::currentMSecsSinceEpoch(); m_searchReady = false; + QString targetDir, sourceDir; for (int ix = 0; ix < m_sourceDirs.size(); ix++){ - processOneDirectory(m_sourceDirs.at(ix), m_targetBaseDir, ix); + sourceDir = m_sourceDirs.at(ix); + targetDir = m_targetDirs.at(ix) + ReFileUtils::nodeOf(sourceDir); + processOneDirectory(sourceDir, targetDir, ix); } m_searchReady = true; - m_mainWindow->externalLog(tr("%1 matching file(s) under %2 with %3 in %4 subdirs %5") - .arg(m_matchedFiles).arg(m_totalFiles) - .arg(ReQStringUtils::readableSize(m_matchedBytes)) - .arg(m_totalDirs) - .arg(ReQStringUtils::readableDuration( - QDateTime::currentMSecsSinceEpoch() - start))); + m_mainWindow->externalLog(tr( + "Search finished: to copy: %1 with %2 matching: %3 total: %4 " + "subdirs: %5 runtime: %6") + .arg(m_hotFiles) + .arg(ReQStringUtils::readableSize(m_hotBytes)) + .arg(m_matchedFiles).arg(m_totalFiles) + .arg(m_totalDirs) + .arg(ReQStringUtils::readableDuration( + QDateTime::currentMSecsSinceEpoch() - start))); } /** * Search the files to backup and write it to a list. @@ -148,15 +157,21 @@ void SearchTask::processOneDirectory(const QString& source, m_totalFiles++; m_mutex.unlock(); } else { - bool doCopy = target.isEmpty(); - if (! doCopy){ + qint64 diff = 0; + bool doCopy = false; + if (target.isEmpty()) + doCopy = true; + else { QFileInfo trg(target + it.fileName()); if (! trg.exists()) doCopy = true; else { const QFileInfo src = it.fileInfo(); - doCopy = trg.exists() && (trg.size() != src.size() - || src.lastModified() > trg.lastModified()); + if (trg.size() != src.size()) + doCopy = true; + else if ((diff = src.lastModified().toMSecsSinceEpoch() + - trg.lastModified().toMSecsSinceEpoch()) > 2000) + doCopy = true; } } if (doCopy){ @@ -166,10 +181,11 @@ void SearchTask::processOneDirectory(const QString& source, m_mutex.lock(); if (doCopy){ m_files.append(info); + m_hotFiles++; + m_hotBytes += it.fileInfo().size(); } m_totalFiles++; m_matchedFiles++; - m_matchedBytes += it.fileInfo().size(); m_mutex.unlock(); } } @@ -188,9 +204,11 @@ void SearchTask::processOneDirectory(const QString& source, if (target.isEmpty()) subTarget.clear(); else{ - subTarget = target + it2.fileName() + OS_2nd_SEPARATOR_STR; + subTarget = target + it2.fileName(); if (! ReFileUtils::isDirectory(subTarget)) subTarget.clear(); + else + subTarget += OS_SEPARATOR_STR; processOneDirectory(it2.filePath(), subTarget, index); m_mutex.lock(); m_totalDirs++; @@ -225,28 +243,36 @@ BackupTask::BackupTask(const QString& name, * @param relpath the path relative to the base path, e.g. "abc/" * @param node the node of source and target */ -void BackupTask::copyFile(int index, const QString& relPath, const QString& node){ +void BackupTask::copyFile(int index, const QString& relPath, + const QString& node){ + qint64 start = QDateTime::currentMSecsSinceEpoch(); QString source = m_sourceDirs.at(index) + relPath + node; - QString targetDir = m_targetDirs.at(index) + relPath; - QString target = targetDir + node; - ReQStringUtils::chomp(targetDir, OS_SEPARATOR); - bool isFile; - if (! ReFileUtils::isDirectory(targetDir, &isFile)){ - if (isFile){ - if (unlink(I18N::s2b(targetDir).constData()) != 0) - error(tr("cannot remove file (for making a directory (%1): %2") - .arg(errno).arg(targetDir)); - } - if (! ReFileUtils::makeDirWithParents(targetDir)) - error(tr("cannot make directory (%1): %2").arg(errno).arg(targetDir)); - } - QFile src(source); - unlink(I18N::s2b(target).constData()); - if (! src.copy(target)){ - error(tr("copy failed (%1): %2").arg(errno).arg(source)); - } else { - m_mainWindow->addToFileList(source); - } + QString targetDir = m_targetDirs.at(index) + relPath; + QString target = targetDir + node; + ReQStringUtils::chomp(targetDir, OS_SEPARATOR); + bool isFile; + if (! ReFileUtils::isDirectory(targetDir, &isFile)){ + if (isFile){ + if (unlink(I18N::s2b(targetDir).constData()) != 0) + error(tr("cannot remove file (for making a directory (%1): %2") + .arg(errno).arg(targetDir)); + } + if (! ReFileUtils::makeDirWithParents(targetDir)) + error(tr("cannot make directory (%1): %2").arg(errno).arg(targetDir)); + } + QFileInfo info(source); + m_mainWindow->addToFileList(source + " " + ReQStringUtils::readableSize(info.size())); + m_processedFiles++; + m_processedBytes += info.size(); + + QString errorMsg = ReFileUtils::copy(source, target, &info, m_buffer); + if (! errorMsg.isEmpty()){ + error(errorMsg); + m_mainWindow->expandFileList(errorMsg); + } else { + m_mainWindow->expandFileList(ReQStringUtils::readableDuration( + QDateTime::currentMSecsSinceEpoch() - start)); + } } /** @@ -256,6 +282,7 @@ void BackupTask::run() { QString relPath, node; QString info; + qint64 start = QDateTime::currentMSecsSinceEpoch(); while (true){ m_mutex.lock(); if (m_files.size() == 0) @@ -279,7 +306,19 @@ void BackupTask::run() relPath = info.mid(1, pos - 1); node = info.mid(pos + 1); copyFile(index, relPath, node); + qint64 now = QDateTime::currentMSecsSinceEpoch(); + qint64 estimated = (now - start) * m_hotBytes / max(1LL, m_processedBytes); + m_mainWindow->externalAppend(ReGuiQueueItem::StatusLine, NULL, + tr("%1 of %2 (%3 of %4) %5 MB/sec Remaining: %6 of %7") + .arg(m_processedFiles).arg(m_hotFiles) + .arg(ReQStringUtils::readableSize(m_processedBytes)) + .arg(ReQStringUtils::readableSize(m_hotBytes)) + .arg(m_processedBytes / 1024.0 / 1024 / (now - start) * 1000, 0, 'f', 3) + .arg(ReQStringUtils::readableDuration(estimated - (now - start))) + .arg(ReQStringUtils::readableDuration(estimated))); } } - m_mainWindow->externalTaskFinished("ready"); + m_mainWindow->externalTaskFinished(tr("backup complete after ") + + ReQStringUtils::readableDuration( + QDateTime::currentMSecsSinceEpoch() - start)); } diff --git a/appl/rebackgui/BackupEngine.hpp b/appl/rebackgui/BackupEngine.hpp index 889294a..07f0a1f 100644 --- a/appl/rebackgui/BackupEngine.hpp +++ b/appl/rebackgui/BackupEngine.hpp @@ -33,7 +33,10 @@ protected: public: static bool m_shouldStop; static QStringList m_files; - static qint64 m_matchedBytes; + static qint64 m_hotBytes; + static int m_processedFiles; + static qint64 m_processedBytes; + static int m_hotFiles; static int m_matchedFiles; static int m_totalFiles; static int m_totalDirs; @@ -69,9 +72,11 @@ public: public: virtual void run(); protected: - void copyFile(int index, const QString& relpath, const QString& node); + void copyFile(int index, const QString& relpath, + const QString& node); private: QString m_lastRelPath; + QByteArray m_buffer; }; #endif // BACKUPPROCESSOR_HPP diff --git a/appl/rebackgui/BackupUtils.cpp b/appl/rebackgui/BackupUtils.cpp index ee777f6..df85b27 100644 --- a/appl/rebackgui/BackupUtils.cpp +++ b/appl/rebackgui/BackupUtils.cpp @@ -19,8 +19,8 @@ BackupUtils::BackupUtils() */ QString BackupUtils::dateToString(const QDateTime &dateTime) { - QString rc = dateTime.toString("yyyy.MM.dd/hh:mm:ss"); - return rc; + QString rc = dateTime.toString("yyyy.MM.dd/hh:mm:ss"); + return rc; } /** @@ -35,33 +35,39 @@ QString BackupUtils::dateToString(const QDateTime &dateTime) */ QString BackupUtils::findTarget(const BackupItem& item, ReLogger* logger) { - QString rc; + QString rc; #if defined __linux__ + if (item.m_target.startsWith(";/")){ + // the path is an absolute path on a fixed disk: + rc = item.m_target.mid(1); + } else { + + } #elif defined _WIN32 - QStringList drives = ReFileUtils::findRootDirs(); - QStringList::const_iterator it; - for (it = drives.cbegin(); it != drives.cend(); ++it){ - QString path = *it; - ReQStringUtils::ensureLastChar(path, OS_SEPARATOR); - int pos = item.m_target.indexOf(';'); - if (pos >= 0) - path += item.m_target.mid(pos + 1); - else - path += item.m_target; - QString markerFile = nameOfTargetDescription(path); - if (QFileInfo(markerFile).exists()){ - if (rc.isEmpty()) - rc = ReFileUtils::parentOf(markerFile); - ReConfig config(I18N::s2b(markerFile), true, logger); - if (! config.asString((item.m_uid + ".created").toLatin1(), - "").isEmpty()){ - rc = ReFileUtils::parentOf(markerFile); - break; - } - } - } + QStringList drives = ReFileUtils::findRootDirs(); + QStringList::const_iterator it; + for (it = drives.cbegin(); it != drives.cend(); ++it){ + QString path = *it; + ReQStringUtils::ensureLastChar(path, OS_SEPARATOR); + int pos = item.m_target.indexOf(';'); + if (pos >= 0) + path += item.m_target.mid(pos + 1); + else + path += item.m_target; + QString markerFile = nameOfTargetDescription(path); + if (QFileInfo(markerFile).exists()){ + if (rc.isEmpty()) + rc = ReFileUtils::parentOf(markerFile); + ReConfig config(I18N::s2b(markerFile), true, logger); + if (! config.asString((item.m_uid + ".created").toLatin1(), + "").isEmpty()){ + rc = ReFileUtils::parentOf(markerFile); + break; + } + } + } #endif - return rc; + return rc; } /** @@ -71,10 +77,10 @@ QString BackupUtils::findTarget(const BackupItem& item, ReLogger* logger) * @return the full name of the file */ QString BackupUtils::nameOfTargetDescription(const QString& path){ - QString fname = path; - ReQStringUtils::ensureLastChar(fname, OS_SEPARATOR); - fname += ".rebackgui.target"; - return fname; + QString fname = path; + ReQStringUtils::ensureLastChar(fname, OS_SEPARATOR); + fname += ".rebackgui.target"; + return fname; } /** @@ -88,17 +94,17 @@ QString BackupUtils::nameOfTargetDescription(const QString& path){ * @return true: target is already initialized */ bool BackupUtils::prepareTarget(const QString& path, BackupItem &item, - ReLogger* logger) + ReLogger* logger) { - bool rc = false; - QString fname = nameOfTargetDescription(path); - ReConfig config(I18N::s2b(fname), false, logger); - QByteArray key = item.m_uid.toLatin1() + ".created"; - if (config.asString(key.constData(), "").isEmpty()){ - config.put(key, dateToString(QDateTime::currentDateTime()).toLatin1().constData()); - rc = true; - } - return rc; + bool rc = false; + QString fname = nameOfTargetDescription(path); + ReConfig config(I18N::s2b(fname), false, logger); + QByteArray key = item.m_uid.toLatin1() + ".created"; + if (config.asString(key.constData(), "").isEmpty()){ + config.put(key, dateToString(QDateTime::currentDateTime()).toLatin1().constData()); + rc = true; + } + return rc; } /** @@ -109,9 +115,9 @@ bool BackupUtils::prepareTarget(const QString& path, BackupItem &item, */ QDateTime BackupUtils::stringToDate(const QString &dateTime) { - QDateTime rc; - rc.fromString(dateTime, "yyyy.MM.dd/hh:mm:ss"); - return rc; + QDateTime rc; + rc.fromString(dateTime, "yyyy.MM.dd/hh:mm:ss"); + return rc; } diff --git a/appl/rebackgui/mainwindow.cpp b/appl/rebackgui/mainwindow.cpp index 26b06a9..4a03b99 100644 --- a/appl/rebackgui/mainwindow.cpp +++ b/appl/rebackgui/mainwindow.cpp @@ -93,6 +93,17 @@ void MainWindow::addToFileList(const QString info){ externalAppend(ReGuiQueueItem::ListEnd, ui->listWidgetFile, info); } +/** + * Appends a string to the current line in the filelist. + * + * Note: this method is called by a non main thread. + * + * @param info info to add + */ +void MainWindow::expandFileList(const QString info){ + externalAppend(ReGuiQueueItem::ListAppendToCurrent, ui->listWidgetFile, info); +} + /** * Issues an error message. * @@ -113,19 +124,19 @@ bool MainWindow::error(const QString& message){ * @return the relative path */ QString MainWindow::extractTarget(const QString& dir){ - QString rc; - QString target; + QString rc; + QString target; #if defined __linux__ #elif defined _WIN32 - rc = dir; - if (dir.length() >= 2 && dir.at(1) == ':') - rc.remove(0, 2); - if (rc.startsWith(OS_SEPARATOR_STR)) - rc.remove(0, 1); - target = ";" + rc; + rc = dir; + if (dir.length() >= 2 && dir.at(1) == ':') + rc.remove(0, 2); + if (rc.startsWith(OS_SEPARATOR_STR)) + rc.remove(0, 1); + target = ";" + rc; #endif - ui->lineEditTarget->setText(target); - return rc; + ui->lineEditTarget->setText(target); + return rc; } /** @@ -285,11 +296,11 @@ void MainWindow::onSelectTarget(){ QFileDialog::ShowDirsOnly); if (!dir.isEmpty()){ dir = ReFileUtils::nativePath(dir); - extractTarget(dir); - BackupItem& item = m_configuration.items()[m_currentRowConfiguration]; - if (! BackupUtils::prepareTarget(dir, item, &m_logger)) - say(LOG_INFO, tr("target initialized with %1") - .arg(BackupUtils::nameOfTargetDescription(dir))); + extractTarget(dir); + BackupItem& item = m_configuration.items()[m_currentRowConfiguration]; + if (! BackupUtils::prepareTarget(dir, item, &m_logger)) + say(LOG_INFO, tr("target initialized with %1") + .arg(BackupUtils::nameOfTargetDescription(dir))); } } /** @@ -327,25 +338,33 @@ void MainWindow::onStart(){ if (row < 0){ say(LOG_ERROR, tr("no backup item selected")); } else { - const BackupItem& item = m_configuration.items().at(row); + const BackupItem& item = m_configuration.items().at(row); BackupEngine::m_searchReady = false; - QString target = BackupUtils::findTarget(item, &m_logger); - if (target.isEmpty()){ - say(LOG_ERROR, tr("Target not available")); - } else { - ReQStringUtils::ensureLastChar(target, OS_SEPARATOR); - startStop(true); - delete m_searchTask; - m_searchTask = new SearchTask(item.m_name, - item.m_filePatterns, item.m_dirPatterns, - item.m_sources, target, this); - m_searchTask->start(); - delete m_backupTask; - m_backupTask = new BackupTask(item.m_name, item.m_sources, target, - this); - m_backupTask->start(); - } - } + BackupEngine::m_hotBytes = 0; + BackupEngine::m_hotFiles = 0; + BackupEngine::m_matchedFiles = 0; + BackupEngine::m_totalDirs = 0; + BackupEngine::m_totalFiles = 0; + BackupEngine::m_processedFiles = 0; + BackupEngine::m_processedBytes = 0; + + QString target = BackupUtils::findTarget(item, &m_logger); + if (target.isEmpty()){ + say(LOG_ERROR, tr("Target not available")); + } else { + ReQStringUtils::ensureLastChar(target, OS_SEPARATOR); + startStop(true); + delete m_searchTask; + m_searchTask = new SearchTask(item.m_name, + item.m_filePatterns, item.m_dirPatterns, + item.m_sources, target, this); + m_searchTask->start(); + delete m_backupTask; + m_backupTask = new BackupTask(item.m_name, item.m_sources, target, + this); + m_backupTask->start(); + } + } } /** * Stops the backup. @@ -488,7 +507,7 @@ void MainWindow::updateTableRow(int row, BackupItem& item, QTableWidget* target) target->setItem(row, base + 0, new QTableWidgetItem(item.m_name)); target->setItem(row, base + 1, new QTableWidgetItem(item.m_target)); target->setItem(row, base + 2, new QTableWidgetItem(! item.m_lastBackup.isValid() ? "" : - BackupUtils::dateToString(item.m_lastBackup))); + BackupUtils::dateToString(item.m_lastBackup))); target->setItem(row, base + 3, new QTableWidgetItem(item.m_sources.join(" "))); } } diff --git a/appl/rebackgui/mainwindow.hpp b/appl/rebackgui/mainwindow.hpp index 0305348..c3c96fc 100644 --- a/appl/rebackgui/mainwindow.hpp +++ b/appl/rebackgui/mainwindow.hpp @@ -26,6 +26,7 @@ public: void addToFileList(const QString info); QString buildTargetDir(const QString& target); bool error(const QString& message); + void expandFileList(const QString info); bool log(const QString& message); virtual bool say(ReLoggerLevel level, const QString& message); void setStatusMessage(bool error, const QString& message); @@ -63,7 +64,7 @@ private: int m_currentRowBackup; QString m_lastSource; SearchTask* m_searchTask; - BackupTask* m_backupTask; + BackupTask* m_backupTask; }; #endif // MAINWINDOW_HPP diff --git a/base/ReFileUtils.cpp b/base/ReFileUtils.cpp index e2bae9e..35a69f4 100644 --- a/base/ReFileUtils.cpp +++ b/base/ReFileUtils.cpp @@ -117,6 +117,76 @@ QString ReFileUtils::cleanPath(const QString& path) { return (QString) cleanPath(I18N::s2b(path).constData()); } +/** + * Copies a file with content and metadata (datetime, permissions). + * + * @param source full path of the source file + * @param target full path of the target name + * @param sourceInfo NULL or the info about the surce + * @param buffer IN/OUT: used as + * @return + */ +QString ReFileUtils::copy(const QString& source, const QString& target, + const QFileInfo* sourceInfo, QByteArray& buffer){ + QString rc; + QByteArray source2 = I18N::s2b(source); + QByteArray target2 = I18N::s2b(target); + QFileInfo sourceInfo2; + if (sourceInfo == NULL){ + sourceInfo2.setFile(source); + sourceInfo = &sourceInfo2; + } + if (! sourceInfo->exists()) + rc = QObject::tr("not found: %1").arg(source); + else { + FILE* fpSource = fopen(source2.constData(), "rb"); + if (fpSource == NULL){ + rc = QObject::tr("cannot open (%1): %2").arg(errno).arg(source); + } else { + FILE* fpTarget = fopen(I18N::s2b(target).constData(), "wb"); + if (fpTarget == NULL){ + rc = QObject::tr("cannot open (%1): %2").arg(errno).arg(target); + } else { + qint64 filesize = sourceInfo->size(); + int blockSize = max(buffer.capacity(), 1024*1024); + buffer.resize(blockSize); + int readBytes, writeBytes; + bool again = true; + char* bufferPtr = buffer.data(); + qint64 totalBytes = 0; + while(again){ + if ( (readBytes = fread(bufferPtr, 1, blockSize, fpSource)) <= 0) + again = false; + if (readBytes > 0){ + totalBytes += readBytes; + if ( (writeBytes = fwrite(bufferPtr, 1, readBytes, fpTarget)) + != readBytes){ + again = false; + rc = QObject::tr("cannot write (%1): $2 [%3/%4]").arg(errno) + .arg(target).arg(readBytes).arg(writeBytes); + } + } + } + fclose(fpTarget); + if (totalBytes < filesize) + rc = QObject::tr("file can be read only partitionally: %1 [%2/%3]") + .arg(source).arg(totalBytes).arg(filesize); + if (rc.isEmpty()){ + if (! setTimes(target2, sourceInfo->lastModified(), + sourceInfo->lastRead())) + rc = QObject::tr("cannot set date/time (%1): %2") + .arg(errno).arg(target); + if (! setPermissions(target2, sourceInfo->permissions())) + rc = QObject::tr("cannot set permissions (%1): %2") + .arg(errno).arg(target); + } + } + fclose(fpSource); + } + } + return rc; +} + /** * Delete a directory tree. * @@ -230,7 +300,7 @@ QByteArray ReFileUtils::extensionOf(const char* filename) { ix--; } } - return rc; + return rc; } /** @@ -242,17 +312,17 @@ QByteArray ReFileUtils::extensionOf(const char* filename) { */ QStringList ReFileUtils::findRootDirs() { - QStringList rc; + QStringList rc; #if defined __linux__ - rc.append("/"); + rc.append("/"); #elif defined _WIN32 - QFileInfoList drives = QDir::drives(); - QFileInfoList::const_iterator it; - for (it = drives.cbegin(); it != drives.cend(); ++it){ - rc.append(it->absolutePath().mid(0, 2)); - } + QFileInfoList drives = QDir::drives(); + QFileInfoList::const_iterator it; + for (it = drives.cbegin(); it != drives.cend(); ++it){ + rc.append(it->absolutePath().mid(0, 2)); + } #endif - return rc; + return rc; } /** @@ -305,10 +375,10 @@ bool ReFileUtils::isDirectory(const QString& path, bool* isFile) if (rc){ if (! info.isDir()) rc = false; - if (isFile != NULL) - *isFile = ! rc; - } else if (isFile != NULL) - *isFile = false; + if (isFile != NULL) + *isFile = ! rc; + } else if (isFile != NULL) + *isFile = false; return rc; } @@ -323,10 +393,41 @@ bool ReFileUtils::isRootDir(const char* path) #if defined __linux__ return path[0] == OS_SEPARATOR && path[1] == '\0'; #elif defined _WIN32 - return isalpha(path[0]) && path[1] == ':' && path[2] == '\\' && path[3] == '\0'; + return isalpha(path[0]) && path[1] == ':' && path[2] == '\\' && path[3] == '\0'; #endif } +/** + * Converts QT permissions into linux permissions. + * + * @param permissions QT permissions, + * e.g. QFile::ReadOwner | QFile::WriteGroup + * @return the permissions used by linux, + * e.G. S_IRUSR | S_IWGRP + */ +mode_t ReFileUtils::linuxPermissions(QFile::Permissions permissions){ + mode_t rc = 0; + if (permissions.testFlag(QFile::ReadOwner)) + rc |= S_IRUSR; + if (permissions.testFlag(QFile::ReadGroup)) + rc |= S_IRGRP; + if (permissions.testFlag(QFile::ReadOther)) + rc |= S_IROTH; + if (permissions.testFlag(QFile::WriteOwner)) + rc |= S_IWUSR; + if (permissions.testFlag(QFile::WriteGroup)) + rc |= S_IWGRP; + if (permissions.testFlag(QFile::WriteOther)) + rc |= S_IWOTH; + if (permissions.testFlag(QFile::ExeOwner)) + rc |= S_IXUSR; + if (permissions.testFlag(QFile::ExeGroup)) + rc |= S_IXGRP; + if (permissions.testFlag(QFile::ExeOther)) + rc |= S_IXOTH; + return rc; +} + /** * Creates a directory (if not it does not exist) and logs errors. * @@ -371,39 +472,40 @@ bool ReFileUtils::makeDir(const QString& path, ReLogger* logger) { * false: error occurred */ bool ReFileUtils::makeDirWithParents(const char* path, ReLogger* logger) { - struct stat info; - bool rc = false; - if (stat(path, &info) == 0 && S_ISDIR(info.st_mode)){ - rc = true; - } else { - QByteArray dir = ReStringUtils::chomp(parentOf(path), OS_SEPARATOR); - if (stat(dir.constData(), &info) == 0 && S_ISDIR(info.st_mode)) - rc = makeDir(path, logger); - else { - const char* end; - const char* start = path; - while (rc && (end = strchr(start, OS_SEPARATOR)) != NULL) { - if (end == path) { - start++; - dir += OS_SEPARATOR; - } else { - dir.append(start, end - start); - start = end + 1; + struct stat info; + bool rc = false; + if (stat(path, &info) == 0 && S_ISDIR(info.st_mode)){ + rc = true; + } else { + QByteArray dir = parentOf(path); + ReStringUtils::chomp(dir, OS_SEPARATOR); + if (stat(dir.constData(), &info) == 0 && S_ISDIR(info.st_mode)) + rc = makeDir(path, logger); + else { + const char* end; + const char* start = path; + while (rc && (end = strchr(start, OS_SEPARATOR)) != NULL) { + if (end == path) { + start++; + dir += OS_SEPARATOR; + } else { + dir.append(start, end - start); + start = end + 1; #if defined _WIN32 - if (dir.length() == 2 && dir.at(1) == ':') - continue; + if (dir.length() == 2 && dir.at(1) == ':') + continue; #endif - rc = makeDir(dir.constData(), logger); - dir += OS_SEPARATOR; - } - } - if (rc && start[0] != '\0') { - dir.append(start); - rc = makeDir(dir.constData(), logger); - } - } - } - return rc; + rc = makeDir(dir.constData(), logger); + dir += OS_SEPARATOR; + } + } + if (rc && start[0] != '\0') { + dir.append(start); + rc = makeDir(dir.constData(), logger); + } + } + } + return rc; } /** @@ -475,17 +577,17 @@ QByteArray ReFileUtils::nodeOf(const char* filename) { * trailing separator */ QString ReFileUtils::parentOf(const QString& filename) { - QString rc; + QString rc; - int ix = filename.size() - 1; - while (ix >= 0) { - if (filename[ix] == '/' || filename[ix] == '\\') { - rc = filename.mid(0, ix + 1); - break; - } - ix--; - } - return rc; + int ix = filename.size() - 1; + while (ix >= 0) { + if (filename[ix] == '/' || filename[ix] == '\\') { + rc = filename.mid(0, ix + 1); + break; + } + ix--; + } + return rc; } /** @@ -498,17 +600,17 @@ QString ReFileUtils::parentOf(const QString& filename) { * trailing separator */ QByteArray ReFileUtils::parentOf(const char* filename) { - QByteArray rc; + QByteArray rc; - int ix = strlen(filename) - 1; - while (ix >= 0) { - if (filename[ix] == '/' || filename[ix] == '\\') { - rc.append(filename, ix + 1); - break; - } - ix--; - } - return rc; + int ix = strlen(filename) - 1; + while (ix >= 0) { + if (filename[ix] == '/' || filename[ix] == '\\') { + rc.append(filename, ix + 1); + break; + } + ix--; + } + return rc; } /** @@ -680,6 +782,26 @@ void ReFileUtils::splitUrl(const QString& url, QString* protocol, QString* host, } } +/** + * Sets the permissions. + * + * @param filename name of the file to change + * @param permissions the permissions to set. + * @param logger the logger + * @return true: success + */ +bool ReFileUtils::setPermissions(const char* filename, + QFile::Permissions permissions, ReLogger* logger) { + bool rc = true; + if (chmod(filename, linuxPermissions(permissions)) != 0){ + if (logger != NULL) + logger->logv(LOG_ERROR, LOC_SET_TIMES_1, + "cannot change permissions (%d): $s", errno, filename); + rc = false; + } + return rc; +} + /** * Sets the filetimes. * @@ -709,16 +831,16 @@ bool ReFileUtils::setTimes(const char* filename, const QDateTime& modified, rc = false; } #else - // ANSII-C: - struct utimbuf times; - times.actime = time_t(accessed.currentMSecsSinceEpoch() / 1000); - times.modtime = time_t(modified.currentMSecsSinceEpoch() / 1000); - int rc2 = utime(filename, ×); - if (rc2 != 0 && logger != NULL){ - logger->logv(LOG_ERROR, LOC_SET_TIMES_1, - "cannot change times (%d): $s", errno, filename); - rc = false; - } + // ANSII-C: + struct utimbuf times; + times.actime = time_t(accessed.currentMSecsSinceEpoch() / 1000); + times.modtime = time_t(modified.currentMSecsSinceEpoch() / 1000); + int rc2 = utime(filename, ×); + if (rc2 != 0 && logger != NULL){ + logger->logv(LOG_ERROR, LOC_SET_TIMES_1, + "cannot change times (%d): $s", errno, filename); + rc = false; + } #endif return rc; } @@ -737,7 +859,7 @@ int ReFileUtils::seek(FILE* file, int64_t offset, int whence) { #if defined __linux__ rc = fseeko(file, offset, whence); #elif defined _WIN32 - rc = _fseeki64(file, offset, whence); + rc = _fseeki64(file, offset, whence); #endif return rc; } @@ -754,7 +876,7 @@ int64_t ReFileUtils::tell(FILE* file) { #if defined __linux__ rc = ftello(file); #elif defined _WIN32 - rc = _ftelli64(file); + rc = _ftelli64(file); #endif return rc; } diff --git a/base/ReFileUtils.hpp b/base/ReFileUtils.hpp index db12853..2aed733 100644 --- a/base/ReFileUtils.hpp +++ b/base/ReFileUtils.hpp @@ -32,6 +32,8 @@ public: ReLogger* logger = NULL); static QByteArray cleanPath(const char* path); static QString cleanPath(const QString& path); + static QString copy(const QString& source, const QString& target, + const QFileInfo* sourceInfo, QByteArray& buffer); static QString extensionOf(const QString& filename); static QByteArray extensionOf(const char* filename); static QStringList findRootDirs(); @@ -39,6 +41,7 @@ public: static bool isAbsolutPath(const char* path); static bool isDirectory(const QString& path, bool* isFile = NULL); static bool isRootDir(const char* path); + static mode_t linuxPermissions(QFile::Permissions permissions); /** Returns a path with native separators. * QT under windows can operator with 2 separators: '\\' and '/'. * '\\' is the native separator. @@ -79,6 +82,9 @@ public: static QString replaceExtension(const QString& path, const QString& ext); static QByteArray replaceExtension(const char* path, const char* ext); static int seek(FILE* file, int64_t offset, int whence); + static bool setPermissions(const char* filename, + QFile::Permissions permissions, + ReLogger* logger = NULL); static bool setTimes(const char* filename, const QDateTime& modified, const QDateTime& accessed = m_undefinedTime, ReLogger* logger = NULL); static void splitUrl(const QString& url, QString* protocol, QString* host, diff --git a/base/ReQStringUtils.cpp b/base/ReQStringUtils.cpp index b5fcf72..74d2c23 100644 --- a/base/ReQStringUtils.cpp +++ b/base/ReQStringUtils.cpp @@ -505,30 +505,30 @@ void ReQStringUtils::skipExpected(const ReString& text, QChar expected, /** * Returns a readable string for a duration given by clock_t. * - * @param duration a duration in msec + * @param durationMilliSec a duration in msec * * @return a string describing the duration. */ -QString ReQStringUtils::readableDuration(qint64 duration){ +QString ReQStringUtils::readableDuration(qint64 durationMilliSec){ QString rc; char buffer[128]; - double duration2 = (double) duration / 1000; + double duration2 = (double) durationMilliSec / 1000; if (duration2 < 60.0){ rc = QString::number(duration2, 'f', 3) + " sec"; } else if (duration2 < 3600.0){ int duration3 = int(duration2); - _snprintf(buffer, sizeof buffer, "%d:%02d", + _snprintf(buffer, sizeof buffer, "%d:%02d", duration3 / 60, duration3 % 60); rc = buffer; } else if (duration2 < 3600.0 * 24){ int duration3 = int(duration2); - _snprintf(buffer, sizeof buffer, "%d:%02d:%02d", + _snprintf(buffer, sizeof buffer, "%d:%02d:%02d", duration3 / 3600, duration3 % 3600 / 60, duration3 % 60); rc = buffer; } else { int duration3 = int(duration2); - _snprintf(buffer, sizeof buffer, "%d:%02d:%02d:%02d", + _snprintf(buffer, sizeof buffer, "%d:%02d:%02d:%02d", int(duration3 / (3600*24)), int(duration3 % (3600*24) / 3600), int(duration3 % 3600 / 60), int(duration3 % 60)); diff --git a/base/ReQStringUtils.hpp b/base/ReQStringUtils.hpp index a82853a..bdb9f28 100644 --- a/base/ReQStringUtils.hpp +++ b/base/ReQStringUtils.hpp @@ -73,7 +73,7 @@ public: return path; #endif } - static QString readableDuration(qint64 duration); + static QString readableDuration(qint64 durationMilliSec); static QString readableSize(int64_t filesize); static bool replacePlaceholders(QString& text, const QMap& placeholders, QString* error); diff --git a/base/ReRandomizer.cpp b/base/ReRandomizer.cpp index 92ce55f..a2ad003 100644 --- a/base/ReRandomizer.cpp +++ b/base/ReRandomizer.cpp @@ -10,6 +10,7 @@ */ #include "base/rebase.hpp" +#include //#define WITH_TRACE #include "retrace.hpp" enum { @@ -365,17 +366,24 @@ const QByteArray& ReRandomizer::name() const { */ ReRandomizer::seed_t ReRandomizer::pseudoTrueRandom(){ clock_t random = clock(); - time_t random2 = time(NULL); + quint64 random2 = QDateTime::currentMSecsSinceEpoch(); + quint64 random3 = hash(QDir::homePath().toLatin1()) + + (hash(QDir::currentPath().toLocal8Bit()) << 15); + QStorageInfo storage = QStorageInfo::root(); + qint64 random4 = storage.bytesAvailable(); + static int s_counter = 0; void* dummy2 = malloc(1); free(dummy2); - seed_t rc = (((seed_t) random2) << 31) + (seed_t) random + seed_t rc = (((seed_t) random2) << 25) + (seed_t) random + ((seed_t) &s_counter << 9) + + random3 + ((-random ^ 0x20111958) ^ (seed_t(dummy2))); rc = (rc * m_primes64[int(rc % m_countPrimes)] + (m_primes64[int((rc >> 13) % m_countPrimes)] >> 1)) ^ m_primes64[++s_counter % m_countPrimes]; - rc = (rc << 56) | (uint64_t(rc) >> (64 - 56)); + + rc = ((rc << 56) | (quint64(rc) >> (64 - 56))) + random4; return rc; } @@ -393,7 +401,7 @@ ReRandomizer::seed_t ReRandomizer::nearTrueRandom() { rc ^= buffer; close(fh); #endif - return rc; + return rc; } /** @@ -404,16 +412,16 @@ ReRandomizer::seed_t ReRandomizer::nearTrueRandom() { */ QByteArray ReRandomizer::buildUUID(bool readable) { - QByteArray uuid; - uint8_t buffer[2 * sizeof(seed_t)]; - reinterpret_cast(buffer)[0] = nearTrueRandom(); - reinterpret_cast(buffer)[1] = nearTrueRandom(); - ReStringUtils::base64Encode(buffer, 12, uuid); - if (readable){ - for (int ix = 12; ix > 0; ix -= 4) - uuid.insert(ix, '-'); - } - return uuid; + QByteArray uuid; + uint8_t buffer[2 * sizeof(seed_t)]; + reinterpret_cast(buffer)[0] = nearTrueRandom(); + reinterpret_cast(buffer)[1] = nearTrueRandom(); + ReStringUtils::base64Encode(buffer, 12, uuid); + if (readable){ + for (int ix = 12; ix > 0; ix -= 4) + uuid.insert(ix, '-'); + } + return uuid; } /** @@ -508,7 +516,7 @@ int64_t ReRandomizer::nextInt64(int64_t maxValue, int64_t minValue) { rc = minValue; else if (minValue == 0 && maxValue == LLONG_MAX) rc = abs((int64_t) seed); - else if (uint64_t(maxValue - minValue) < LLONG_MAX) + else if (qint64(maxValue - minValue) < LLONG_MAX) // no signed int64 overflow: rc = minValue + seed % (maxValue - minValue + 1); else { @@ -847,7 +855,7 @@ ReRotateRandomizer::ReRotateRandomizer() : ReRandomizer::seed_t ReRotateRandomizer::nextSeed64() { seed_t rc = ReCongruentialGenerator::nextSeed64(); - rc = ((rc << 33) | (uint64_t(rc) >> 31)); + rc = ((rc << 33) | (quint64(rc) >> 31)); ++m_counter; return rc; } @@ -884,7 +892,7 @@ ReRandomizer::seed_t ReMultiCongruentialGenerator::nextSeed64() { seed_t rc = m_seeds[m_currentSeed] * m_primes64[ixFactor] + (m_primes64[ixFactor + 1] >> 1); m_seeds[m_currentSeed] = rc; - rc = (rc << 33) | (uint64_t(rc) >> (64-33)); + rc = (rc << 33) | (quint64(rc) >> (64-33)); ++m_counter; return rc; } @@ -1079,7 +1087,7 @@ void ReKISSRandomizer::saveSeed(QByteArray& seed) const { */ QByteArray ReKISSRandomizer::state() const{ char buffer[512]; - _snprintf(buffer, sizeof buffer, + _snprintf(buffer, sizeof buffer, "%2d: f: %016llx i: %016llx: c: %016llx x: %016llx y: %016llx z: %016llx", m_counter, (long long) m_factor, (long long) m_increment, diff --git a/base/ReStringUtils.cpp b/base/ReStringUtils.cpp index 9e2c8ea..7039125 100644 --- a/base/ReStringUtils.cpp +++ b/base/ReStringUtils.cpp @@ -28,7 +28,7 @@ const char ReStringUtils::AUTO_SEPARATOR = '\0'; const QByteArray ReStringUtils::m_empty; static const char* m_base64Chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /** @@ -40,25 +40,25 @@ static const char* m_base64Chars = * @return output (for chaining) */ QByteArray& ReStringUtils::base64Decode(const char* input, int inputLength, QByteArray& output) { - static uint8_t decoder[256] = {0}; - if (decoder['A'] == 0){ - for (int ix = strlen(m_base64Chars) - 1; ix >= 0; ix--) - decoder[m_base64Chars[ix]] = ix; - } - int fillBytes = 0; - while(inputLength > 0 && input[inputLength - 1] == '='){ - fillBytes++; - inputLength--; - } - output.resize((inputLength + 3) * 3 / 4); - uint8_t* outCursor = reinterpret_cast(output.data()); - while(inputLength > 4){ - *outCursor++ = decoder[(input[0] << 2) + ((input[1] & 0x30) >> 4)]; - *outCursor++ = decoder[((input[1] & 0xf) << 4) + ((input[2] & 0x3c) >> 2)]; - *outCursor++ = decoder[((input[2] & 0x3) << 6) + input[3]]; - inputLength -= 4; - input += 4; - } + static uint8_t decoder[256] = {0}; + if (decoder['A'] == 0){ + for (int ix = strlen(m_base64Chars) - 1; ix >= 0; ix--) + decoder[(int) m_base64Chars[ix]] = ix; + } + int fillBytes = 0; + while(inputLength > 0 && input[inputLength - 1] == '='){ + fillBytes++; + inputLength--; + } + output.resize((inputLength + 3) * 3 / 4); + uint8_t* outCursor = reinterpret_cast(output.data()); + while(inputLength > 4){ + *outCursor++ = decoder[(input[0] << 2) + ((input[1] & 0x30) >> 4)]; + *outCursor++ = decoder[((input[1] & 0xf) << 4) + ((input[2] & 0x3c) >> 2)]; + *outCursor++ = decoder[((input[2] & 0x3) << 6) + input[3]]; + inputLength -= 4; + input += 4; + } return output; } @@ -74,23 +74,23 @@ QByteArray& ReStringUtils::base64Encode(uint8_t const* input, size_t inputLength output.resize(4 * ((inputLength + 2 - ((inputLength + 2) % 3)) / 3)); uint8_t* outCursor = reinterpret_cast(output.data()); while (inputLength-- > 3) { - *outCursor++ = m_base64Chars[(input[0] & 0xfc) >> 2]; - *outCursor++ = m_base64Chars[((input[0] & 0x03) << 4) + ((input[1] & 0xf0) >> 4)]; - *outCursor++ = m_base64Chars[((input[1] & 0x0f) << 2) + ((input[2] & 0xc0) >> 6)]; - *outCursor++ = m_base64Chars[input[2] & 0x3f]; - input += 3; - inputLength -= 3; - } + *outCursor++ = m_base64Chars[(input[0] & 0xfc) >> 2]; + *outCursor++ = m_base64Chars[((input[0] & 0x03) << 4) + ((input[1] & 0xf0) >> 4)]; + *outCursor++ = m_base64Chars[((input[1] & 0x0f) << 2) + ((input[2] & 0xc0) >> 6)]; + *outCursor++ = m_base64Chars[input[2] & 0x3f]; + input += 3; + inputLength -= 3; + } if (inputLength > 0){ - uint8_t buffer[3]; - memset(buffer, 0, sizeof buffer); - memcpy(buffer, input, 3 - inputLength); - *outCursor++ = m_base64Chars[(input[0] & 0xfc) >> 2]; - *outCursor++ = m_base64Chars[((input[0] & 0x03) << 4) + ((input[1] & 0xf0) >> 4)]; - *outCursor++ = m_base64Chars[((input[1] & 0x0f) << 2) + ((input[2] & 0xc0) >> 6)]; - *outCursor++ = m_base64Chars[input[2] & 0x3f]; - for (int ii = inputLength; ii <= 3; ii++) - *outCursor++ = '='; + uint8_t buffer[3]; + memset(buffer, 0, sizeof buffer); + memcpy(buffer, input, 3 - inputLength); + *outCursor++ = m_base64Chars[(input[0] & 0xfc) >> 2]; + *outCursor++ = m_base64Chars[((input[0] & 0x03) << 4) + ((input[1] & 0xf0) >> 4)]; + *outCursor++ = m_base64Chars[((input[1] & 0x0f) << 2) + ((input[2] & 0xc0) >> 6)]; + *outCursor++ = m_base64Chars[input[2] & 0x3f]; + for (int ii = inputLength; ii <= 3; ii++) + *outCursor++ = '='; } return output; } @@ -105,7 +105,7 @@ QByteArray& ReStringUtils::base64Encode(uint8_t const* input, size_t inputLength * at the end of the string * @return string: for chaining */ -QByteArray&ReStringUtils::chomp(QByteArray& string, char cc) +QByteArray& ReStringUtils::chomp(QByteArray& string, char cc) { int length; if (string.length() > 0 && string.at(length = string.length() - 1) == cc) diff --git a/base/rebase.hpp b/base/rebase.hpp index e661449..2b9a535 100644 --- a/base/rebase.hpp +++ b/base/rebase.hpp @@ -77,6 +77,7 @@ typedef short int int16_t; #define _mkdir(path) mkdir(path, ALLPERMS) #define _rmdir rmdir #define _unlink unlink +#define _snprintf snprintf //typedef qint64 uint64_t; #else #define S_ISDIR(mode) (((mode) & _S_IFDIR) != 0) diff --git a/gui/ReGuiQueue.cpp b/gui/ReGuiQueue.cpp index 810eef0..da230a0 100644 --- a/gui/ReGuiQueue.cpp +++ b/gui/ReGuiQueue.cpp @@ -99,6 +99,22 @@ bool ReGuiQueueItem::apply() const list->setCurrentRow(list->count() - 1); break; } + case ListAppendToCurrent: + { + QListWidget* list = reinterpret_cast(m_widget); + int count = list->count(); + QListWidgetItem* item = list->item(count - 1); + item->setText(item->text() + " " + m_value); + break; + } + case ListReplaceCurrent: + { + QListWidget* list = reinterpret_cast(m_widget); + int count = list->count(); + QListWidgetItem* item = list->item(count - 1); + item->setText(m_value); + break; + } default: rc = false; break; diff --git a/gui/ReGuiQueue.hpp b/gui/ReGuiQueue.hpp index 0b5775e..97dd4c9 100644 --- a/gui/ReGuiQueue.hpp +++ b/gui/ReGuiQueue.hpp @@ -16,6 +16,7 @@ class ReGuiQueueItem { public: enum WidgetType { Undef, LabelText, NewTableRow, ListEnd, ListAppendToCurrent, + ListReplaceCurrent, LogMessage, LogError, ReadyMessage, StatusLine, UserDefined1, UserDefined2 };