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;
{
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.
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){
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();
}
}
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++;
* @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));
+ }
}
/**
{
QString relPath, node;
QString info;
+ qint64 start = QDateTime::currentMSecsSinceEpoch();
while (true){
m_mutex.lock();
if (m_files.size() == 0)
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));
}
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;
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
*/\r
QString BackupUtils::dateToString(const QDateTime &dateTime)\r
{\r
- QString rc = dateTime.toString("yyyy.MM.dd/hh:mm:ss");\r
- return rc;\r
+ QString rc = dateTime.toString("yyyy.MM.dd/hh:mm:ss");\r
+ return rc;\r
}\r
\r
/**\r
*/\r
QString BackupUtils::findTarget(const BackupItem& item, ReLogger* logger)\r
{\r
- QString rc;\r
+ QString rc;\r
#if defined __linux__\r
+ if (item.m_target.startsWith(";/")){\r
+ // the path is an absolute path on a fixed disk:\r
+ rc = item.m_target.mid(1);\r
+ } else {\r
+\r
+ }\r
#elif defined _WIN32\r
- QStringList drives = ReFileUtils::findRootDirs();\r
- QStringList::const_iterator it;\r
- for (it = drives.cbegin(); it != drives.cend(); ++it){\r
- QString path = *it;\r
- ReQStringUtils::ensureLastChar(path, OS_SEPARATOR);\r
- int pos = item.m_target.indexOf(';');\r
- if (pos >= 0)\r
- path += item.m_target.mid(pos + 1);\r
- else\r
- path += item.m_target;\r
- QString markerFile = nameOfTargetDescription(path);\r
- if (QFileInfo(markerFile).exists()){\r
- if (rc.isEmpty())\r
- rc = ReFileUtils::parentOf(markerFile);\r
- ReConfig config(I18N::s2b(markerFile), true, logger);\r
- if (! config.asString((item.m_uid + ".created").toLatin1(),\r
- "").isEmpty()){\r
- rc = ReFileUtils::parentOf(markerFile);\r
- break;\r
- }\r
- }\r
- }\r
+ QStringList drives = ReFileUtils::findRootDirs();\r
+ QStringList::const_iterator it;\r
+ for (it = drives.cbegin(); it != drives.cend(); ++it){\r
+ QString path = *it;\r
+ ReQStringUtils::ensureLastChar(path, OS_SEPARATOR);\r
+ int pos = item.m_target.indexOf(';');\r
+ if (pos >= 0)\r
+ path += item.m_target.mid(pos + 1);\r
+ else\r
+ path += item.m_target;\r
+ QString markerFile = nameOfTargetDescription(path);\r
+ if (QFileInfo(markerFile).exists()){\r
+ if (rc.isEmpty())\r
+ rc = ReFileUtils::parentOf(markerFile);\r
+ ReConfig config(I18N::s2b(markerFile), true, logger);\r
+ if (! config.asString((item.m_uid + ".created").toLatin1(),\r
+ "").isEmpty()){\r
+ rc = ReFileUtils::parentOf(markerFile);\r
+ break;\r
+ }\r
+ }\r
+ }\r
#endif\r
- return rc;\r
+ return rc;\r
}\r
\r
/**\r
* @return the full name of the file\r
*/\r
QString BackupUtils::nameOfTargetDescription(const QString& path){\r
- QString fname = path;\r
- ReQStringUtils::ensureLastChar(fname, OS_SEPARATOR);\r
- fname += ".rebackgui.target";\r
- return fname;\r
+ QString fname = path;\r
+ ReQStringUtils::ensureLastChar(fname, OS_SEPARATOR);\r
+ fname += ".rebackgui.target";\r
+ return fname;\r
}\r
\r
/**\r
* @return <code>true</code>: target is already initialized\r
*/\r
bool BackupUtils::prepareTarget(const QString& path, BackupItem &item,\r
- ReLogger* logger)\r
+ ReLogger* logger)\r
{\r
- bool rc = false;\r
- QString fname = nameOfTargetDescription(path);\r
- ReConfig config(I18N::s2b(fname), false, logger);\r
- QByteArray key = item.m_uid.toLatin1() + ".created";\r
- if (config.asString(key.constData(), "").isEmpty()){\r
- config.put(key, dateToString(QDateTime::currentDateTime()).toLatin1().constData());\r
- rc = true;\r
- }\r
- return rc;\r
+ bool rc = false;\r
+ QString fname = nameOfTargetDescription(path);\r
+ ReConfig config(I18N::s2b(fname), false, logger);\r
+ QByteArray key = item.m_uid.toLatin1() + ".created";\r
+ if (config.asString(key.constData(), "").isEmpty()){\r
+ config.put(key, dateToString(QDateTime::currentDateTime()).toLatin1().constData());\r
+ rc = true;\r
+ }\r
+ return rc;\r
}\r
\r
/**\r
*/\r
QDateTime BackupUtils::stringToDate(const QString &dateTime)\r
{\r
- QDateTime rc;\r
- rc.fromString(dateTime, "yyyy.MM.dd/hh:mm:ss");\r
- return rc;\r
+ QDateTime rc;\r
+ rc.fromString(dateTime, "yyyy.MM.dd/hh:mm:ss");\r
+ return rc;\r
}\r
\r
\r
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.
*
* @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;
}
/**
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)));
}
}
/**
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.
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(" ")));
}
}
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);
int m_currentRowBackup;
QString m_lastSource;
SearchTask* m_searchTask;
- BackupTask* m_backupTask;
+ BackupTask* m_backupTask;
};
#endif // MAINWINDOW_HPP
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.
*
ix--;
}
}
- return rc;
+ return rc;
}
/**
*/
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;
}
/**
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;
}
#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. <code>QFile::ReadOwner | QFile::WriteGroup</code>
+ * @return the permissions used by linux,
+ * e.G. <code>S_IRUSR | S_IWGRP</code>
+ */
+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.
*
* <code>false</code>: 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;
}
/**
* 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;
}
/**
* 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;
}
/**
}
}
+/**
+ * Sets the permissions.
+ *
+ * @param filename name of the file to change
+ * @param permissions the permissions to set.
+ * @param logger the logger
+ * @return <code>true</code>: 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.
*
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;
}
#if defined __linux__
rc = fseeko(file, offset, whence);
#elif defined _WIN32
- rc = _fseeki64(file, offset, whence);
+ rc = _fseeki64(file, offset, whence);
#endif
return rc;
}
#if defined __linux__
rc = ftello(file);
#elif defined _WIN32
- rc = _ftelli64(file);
+ rc = _ftelli64(file);
#endif
return rc;
}
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();
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.
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,
/**
* Returns a readable string for a duration given by <code>clock_t</code>.
*
- * @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));
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<QString, QString>& placeholders, QString* error);
*/
#include "base/rebase.hpp"
+#include <QStorageInfo>
//#define WITH_TRACE
#include "retrace.hpp"
enum {
*/
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;
}
rc ^= buffer;
close(fh);
#endif
- return rc;
+ return rc;
}
/**
*/
QByteArray ReRandomizer::buildUUID(bool readable)
{
- QByteArray uuid;
- uint8_t buffer[2 * sizeof(seed_t)];
- reinterpret_cast<seed_t*>(buffer)[0] = nearTrueRandom();
- reinterpret_cast<seed_t*>(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<seed_t*>(buffer)[0] = nearTrueRandom();
+ reinterpret_cast<seed_t*>(buffer)[1] = nearTrueRandom();
+ ReStringUtils::base64Encode(buffer, 12, uuid);
+ if (readable){
+ for (int ix = 12; ix > 0; ix -= 4)
+ uuid.insert(ix, '-');
+ }
+ return uuid;
}
/**
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 {
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;
}
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;
}
*/
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,
const QByteArray ReStringUtils::m_empty;
static const char* m_base64Chars =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
* @return <code>output</code> (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<uint8_t*>(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<uint8_t*>(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;
}
output.resize(4 * ((inputLength + 2 - ((inputLength + 2) % 3)) / 3));
uint8_t* outCursor = reinterpret_cast<uint8_t*>(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;
}
* at the end of the string
* @return <code>string</code>: 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)
#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)
list->setCurrentRow(list->count() - 1);
break;
}
+ case ListAppendToCurrent:
+ {
+ QListWidget* list = reinterpret_cast<QListWidget*>(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<QListWidget*>(m_widget);
+ int count = list->count();
+ QListWidgetItem* item = list->item(count - 1);
+ item->setText(m_value);
+ break;
+ }
default:
rc = false;
break;
public:
enum WidgetType {
Undef, LabelText, NewTableRow, ListEnd, ListAppendToCurrent,
+ ListReplaceCurrent,
LogMessage, LogError, ReadyMessage, StatusLine,
UserDefined1, UserDefined2
};