*/
void BackupTask::copyFile(int index, const QString& relPath, const QString& node){
QString source = m_sourceDirs.at(index) + relPath + node;
- QString target = m_targetDirs.at(index) + relPath + node;
- m_mainWindow->addToFileList(source + " -> " + target);
+ 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);
+ }
}
/**
--- /dev/null
+/*\r
+ * Licence:\r
+ * You can use and modify this file without any restriction.\r
+ * There is no warranty.\r
+ * You also can use the licence from http://www.wtfpl.net/.\r
+ * The original sources can be found on https://github.com/republib.\r
+*/\r
+#include "backupgui.hpp"\r
+\r
+BackupUtils::BackupUtils()\r
+{\r
+\r
+}\r
+/**\r
+ * Converts a date time to a string.\r
+ *\r
+ * @param dateTime the timepoint to convert\r
+ * @return the string representation\r
+ */\r
+QString BackupUtils::dateToString(const QDateTime &dateTime)\r
+{\r
+ QString rc = dateTime.toString("yyyy.MM.dd/hh:mm:ss");\r
+ return rc;\r
+}\r
+\r
+/**\r
+ * Finds the real path of a target directory.\r
+ *\r
+ * Note: if the medium of the target is an external medium\r
+ * the path can change.\r
+ *\r
+ * @param item the info about the backup item\r
+ * @return "": not found<br>\r
+ * otherwise: the full path of the target directory\r
+ */\r
+QString BackupUtils::findTarget(const BackupItem& item, ReLogger* logger)\r
+{\r
+ QString rc;\r
+#if defined __linux__\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
+#endif\r
+ return rc;\r
+}\r
+\r
+/**\r
+ * Returns the name of the file marking a backup target.\r
+ *\r
+ * @param path the path of the file\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
+}\r
+\r
+/**\r
+ * Prepares the target base directory.\r
+ *\r
+ * Creates a file. The program uses this file to recognize a target directory.\r
+ *\r
+ * @param path the target base directory\r
+ * @param item the info about the backup item\r
+ * @param logger the logger\r
+ * @return <code>true</code>: target is already initialized\r
+ */\r
+bool BackupUtils::prepareTarget(const QString& path, BackupItem &item,\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
+}\r
+\r
+/**\r
+ * Converts a string into a date time.\r
+ *\r
+ * @param dateTime the string convert\r
+ * @return the date time\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
+}\r
+\r
+\r
--- /dev/null
+/*\r
+ * Licence:\r
+ * You can use and modify this file without any restriction.\r
+ * There is no warranty.\r
+ * You also can use the licence from http://www.wtfpl.net/.\r
+ * The original sources can be found on https://github.com/republib.\r
+*/\r
+#ifndef BACKUPUTILS_H\r
+#define BACKUPUTILS_H\r
+\r
+\r
+class BackupUtils\r
+{\r
+public:\r
+ BackupUtils();\r
+public:\r
+ static QString dateToString(const QDateTime& dateTime);\r
+ static QString findTarget(const BackupItem& item, ReLogger* logger);\r
+ static QString nameOfTargetDescription(const QString &path);\r
+ static bool prepareTarget(const QString &path, BackupItem &item, ReLogger *logger);\r
+ static QDateTime stringToDate(const QString& dateTime);\r
+};\r
+\r
+#endif // BACKUPUTILS_H\r
*/
BackupItem::BackupItem() :
m_no(0),
+ m_uid(),
m_name(),
m_sources(),
m_target(),
*/
BackupItem::BackupItem(int no) :
m_no(no),
+ m_uid(),
m_name(),
m_sources(),
m_target(),
{
BackupItem item(m_items.size());
item.m_name = QObject::tr("item") + QString::number(item.m_no + 1);
+ item.m_uid = QString(ReRandomizer::buildUUID());
m_items.append(item);
}
if (m_items.size() == 0){
appendNew();
}
+ for (int ix =0; ix < m_items.size(); ix++){
+ BackupItem& item = m_items[ix];
+ if (item.m_uid.isEmpty())
+ item.m_uid = QString(ReRandomizer::buildUUID());
+ }
}
/**
getItem(no, map).m_name = value;
} else if (ReQStringUtils::hasPrefixAndNumber("sources", line2, no, value)){
getItem(no, map).m_sources = value.split(';');
- } else if (ReQStringUtils::hasPrefixAndNumber("target", line2, no, value)){
- getItem(no, map).m_target = value;
- } else if (ReQStringUtils::hasPrefixAndNumber("filepatterns", line2, no, value)){
+ } else if (ReQStringUtils::hasPrefixAndNumber("uid", line2, no, value)){
+ getItem(no, map).m_uid = value;
+ } else if (ReQStringUtils::hasPrefixAndNumber("target", line2, no, value)){
+ getItem(no, map).m_target = value;
+ } else if (ReQStringUtils::hasPrefixAndNumber("filepatterns", line2, no, value)){
getItem(no, map).m_filePatterns = value;
} else if (ReQStringUtils::hasPrefixAndNumber("dirpatterns", line2, no, value)){
getItem(no, map).m_dirPatterns = value;
QByteArray buffer;
for (int ix = 0; ix < m_items.size(); ix++){
BackupItem& item = m_items[ix];
- buffer = "name." + QByteArray::number(ix) + "="
- + item.m_name.toUtf8() + "\n";
- buffer += "sources." + QByteArray::number(ix) + "="
+ buffer = "name." + QByteArray::number(ix) + "="
+ + item.m_name.toUtf8() + "\n";
+ buffer += "uid." + QByteArray::number(ix) + "="
+ + item.m_uid.toUtf8() + "\n";
+ buffer += "sources." + QByteArray::number(ix) + "="
+ item.m_sources.join(';').toUtf8() + "\n";
buffer += "target." + QByteArray::number(ix) + "="
+ item.m_target.toUtf8() + "\n";
buffer += "dirpatterns." + QByteArray::number(ix) + "="
+ item.m_dirPatterns.toUtf8() + "\n";
buffer += "lastbackup." + QByteArray::number(ix) + "="
- + item.m_lastBackup.toString("yyyy.MM.dd/hh:mm") + "\n";
+ + BackupUtils::dateToString(item.m_lastBackup) + "\n";
if (fputs(buffer.constData(), fp) != buffer.length())
m_mainWindow->error(QObject::tr("cannot write (%1): %2").arg(errno)
.arg(filename));
BackupItem(int no);
public:
int m_no;
+ QString m_uid;
QString m_name;
QStringList m_sources;
QString m_target;
#include "gui/regui.hpp"
#include "Configuration.hpp"
#include "BackupEngine.hpp"
+#include "BackupUtils.hpp"
#include "mainwindow.hpp"
#include "ui_mainwindow.h"
SLOT(onLoadConfig()));
connect(ui->actionSaveConfig, SIGNAL(triggered()), this,
SLOT(onSaveConfig()));
- connect(ui->pushButtonDeleteItem, SIGNAL(clicked()), this, SLOT(onNewDeleteItem()));
connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(onAbout()));
connect(ui->tableWidgetConfiguration->selectionModel(),
SIGNAL( selectionChanged(const QItemSelection&, const QItemSelection&)),
connect(ui->pushButtonClearErrorList, SIGNAL(clicked()), this, SLOT(onClearErrorList()));
connect(ui->pushButtonClear, SIGNAL(clicked()), this, SLOT(onClearLog()));
m_configuration.load("");
+ ui->tableWidgetConfiguration->selectRow(0);
updateTable();
updateItem(0);
}
}
+/**
+ * Find the target identification.
+ *
+ * @param dir the directory on the external medium (already mounted)
+ * @return the relative path
+ */
+QString MainWindow::extractTarget(const QString& dir){
+ 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;
+#endif
+ ui->lineEditTarget->setText(target);
+ return rc;
+}
+
/**
* Set GUI elements from the queue when the GUI timer is triggered.
*/
QFileDialog::ShowDirsOnly);
if (!dir.isEmpty()){
dir = ReFileUtils::nativePath(dir);
- findTarget(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)));
}
}
-
-/**
- * Find the target identification.
- *
- * @param dir the directory on the external medium (already mounted)
- */
-void MainWindow::findTarget(const QString& dir){
- QString target = ";" + dir;
-#if defined __linux__
-#else
-#endif
- ui->lineEditTarget->setText(target);
-}
-
/**
* The current row has been changed.
*
m_configuration.save("");
}
-/**
- * Builds the target directory.
- *
- * @return the target directory
- */
-QString MainWindow::buildTargetDir(const QString& target){
- QString rc = target;
- int ix = rc.indexOf(';');
- if (ix == 0)
- rc.remove(0, 1);
- return rc;
-}
-
/**
* Starts the backup.
*/
if (row < 0){
say(LOG_ERROR, tr("no backup item selected"));
} else {
- startStop(true);
- const BackupItem& item = m_configuration.items().at(row);
- delete m_searchTask;
+ const BackupItem& item = m_configuration.items().at(row);
BackupEngine::m_searchReady = false;
- QString target = buildTargetDir(item.m_target);
- ReQStringUtils::ensureLastChar(target, OS_SEPARATOR);
- 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();
- }
+ 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() ? "" :
- item.m_lastBackup.toString("yyyy.MM.dd hh:mm")));
+ BackupUtils::dateToString(item.m_lastBackup)));
target->setItem(row, base + 3, new QTableWidgetItem(item.m_sources.join(" ")));
}
}
void startStop(bool isStart);
void restoreState();
void saveState();
+private:
+ QString extractTarget(const QString& dir);
private slots:
virtual void aboutToQuit();
- void findTarget(const QString& dir);
virtual void guiTimerUpdate();
void onAbout();
void onAddItem();
int m_currentRowBackup;
QString m_lastSource;
SearchTask* m_searchTask;
- BackupTask* m_backupTask;
+ BackupTask* m_backupTask;
};
#endif // MAINWINDOW_HPP
-#-------------------------------------------------
-#
-# Project created by QtCreator 2016-01-18T00:51:17
-#
-#-------------------------------------------------
-
-QT += core gui
-
-greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
-
-TARGET = rebackgui
-TEMPLATE = app
-INCLUDEPATH = ../.. /usr/include/c++/4.9
-
-SOURCES += main.cpp\
- ../../base/ReException.cpp \
- ../../base/ReQStringUtils.cpp \
- ../../base/ReFileUtils.cpp \
- ../../base/ReMatcher.cpp \
- ../../base/ReLogger.cpp \
- ../../gui/ReStateStorage.cpp \
- ../../gui/ReGuiApplication.cpp \
- ../../gui/ReGuiValidator.cpp \
- ../../gui/ReGuiQueue.cpp \
- mainwindow.cpp \
- aboutdialog.cpp \
- Configuration.cpp \
- BackupEngine.cpp
-
-HEADERS += mainwindow.hpp \
- ../../base/rebase.hpp \
- ../../base/ReQStringUtils.hpp \
- ../../gui/ReStateStorage.hpp \
- ../../gui/ReGuiValidator.hpp \
- ../../gui/regui.hpp \
- aboutdialog.hpp \
- Configuration.hpp \
- backupgui.hpp \
- BackupEngine.hpp
-
-FORMS += mainwindow.ui \
- aboutdialog.ui
-
-DISTFILES += \
- ReBackGui.html
-
+#-------------------------------------------------\r
+#\r
+# Project created by QtCreator 2016-01-18T00:51:17\r
+#\r
+#-------------------------------------------------\r
+\r
+QT += core gui\r
+\r
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets\r
+\r
+TARGET = rebackgui\r
+TEMPLATE = app\r
+INCLUDEPATH = ../.. /usr/include/c++/4.9\r
+\r
+SOURCES += main.cpp\\r
+ ../../base/ReException.cpp \\r
+ ../../base/ReConfig.cpp \\r
+ ../../base/ReQStringUtils.cpp \\r
+ ../../base/ReFileUtils.cpp \\r
+ ../../base/ReMatcher.cpp \\r
+ ../../base/ReLogger.cpp \\r
+ ../../base/ReRandomizer.cpp \\r
+ ../../base/ReStringUtils.cpp \\r
+ ../../gui/ReStateStorage.cpp \\r
+ ../../gui/ReGuiApplication.cpp \\r
+ ../../gui/ReGuiValidator.cpp \\r
+ ../../gui/ReGuiQueue.cpp \\r
+ mainwindow.cpp \\r
+ aboutdialog.cpp \\r
+ Configuration.cpp \\r
+ BackupEngine.cpp \\r
+ BackupUtils.cpp\r
+\r
+HEADERS += mainwindow.hpp \\r
+ ../../base/rebase.hpp \\r
+ ../../base/ReQStringUtils.hpp \\r
+ ../../gui/ReStateStorage.hpp \\r
+ ../../gui/ReGuiValidator.hpp \\r
+ ../../gui/regui.hpp \\r
+ aboutdialog.hpp \\r
+ Configuration.hpp \\r
+ backupgui.hpp \\r
+ BackupEngine.hpp \\r
+ BackupUtils.hpp\r
+\r
+FORMS += mainwindow.ui \\r
+ aboutdialog.ui\r
+\r
+DISTFILES += \\r
+ ReBackGui.html\r
+\r
m_lineList(),
m_readOnly(readOnly),
m_logger(logger),
- m_ownLogger(logger == NULL) {
+ m_ownLogger(logger == NULL),
+ m_modified(false){
if (logger == NULL) {
initLogger();
}
* Frees the resources.
*/
ReConfig::~ReConfig() {
+ if (! m_readOnly && m_modified)
+ write(m_file);
if (m_ownLogger)
delete m_logger;
m_logger = NULL;
if (contains(key)) {
rc = (*this)[key];
}
- return rc;
+ return rc;
+}
+
+/**
+ * Puts a boolean variable into the configuration.
+ *
+ * @param key the key of the variable
+ * @param value the value of the variable
+ */
+void ReConfig::put(const char *key, bool value)
+{
+ put(key, value ? "true" : "false");
+}
+
+/**
+ * Puts an integer variable into the configuration.
+ *
+ * @param key the key of the variable
+ * @param value the value of the variable
+ */
+void ReConfig::put(const char *key, int value)
+{
+ put(key, QByteArray::number(value).constData());
+}
+
+/**
+ * Puts a string variable into the configuration.
+ *
+ * @param key the key of the variable
+ * @param value the value of the variable
+ */
+void ReConfig::put(const char *key, const char *value)
+{
+ m_modified = true;
+ if (! contains(key)){
+ m_lineList.append(key + QByteArray("="));
+ }
+ insert(key, value);
}
/**
bool ReConfig::read(const char* file) {
bool rc = true;
m_lineList.reserve(1024);
+ if (file == NULL)
+ file = m_file.constData();
FILE* fp = fopen(file, "r");
if (fp == NULL) {
m_logger->logv(LOG_ERROR, LOC_READ_1, "cannot read: %s", file);
if (m_readOnly)
m_logger->log(LOG_ERROR, LOC_WRITE_1, "cannot write: (readonly");
else {
- m_logger->logv(LOG_ERROR, LOC_WRITE_2, "not implemented: write(%s)",
- file);
- }
+ if (file == NULL){
+ file = m_file.constData();
+ }
+ int pos = 0;
+ QByteArray key;
+ FILE* fp = fopen(file, "w");
+ if (fp == NULL)
+ m_logger->logv(LOG_ERROR, LOC_WRITE_2, "cannot open (%d): %s", errno, file);
+ else {
+ for (int ix = 0; ix < m_lineList.size(); ix++){
+ QByteArray& line = m_lineList[ix];
+ if (isalnum(line[0]) && (pos = line.indexOf('=')) >= 0) {
+ key = line.mid(0, pos);
+ if (contains(key))
+ line = key + "=" + value(key) + "\n";
+ }
+ fputs(line.constData(), fp);
+ }
+ fclose(fp);
+ }
+ }
return rc;
}
#ifndef RECONFIG_HPP
#define RECONFIG_HPP
-class ReConfig: public ReConfigurator, public QHash<QByteArray, QByteArray> {
+class ReConfig: public ReConfigurator, protected QHash<QByteArray, QByteArray> {
public:
ReConfig(const char* file = NULL, bool readOnly = true, ReLogger* logger =
NULL);
virtual ~ReConfig();
public:
- bool read(const char* file);
- bool write(const char* file);
- void clear();
- const QList<QByteArray>& getLines() const;
-
virtual bool asBool(const char* key, bool defaultValue) const;
virtual int asInt(const char* key, int defaultValue) const;
virtual QByteArray asString(const char* key, const char* defaultValue);
+ void clear();
+ const QList<QByteArray>& getLines() const;
+ void put(const char* key, bool value);
+ void put(const char* key, int value);
+ void put(const char* key, const char* value);
+ bool read(const char* file = NULL);
+ bool write(const char* file = NULL);
+
private:
void initLogger();
private:
- const char* m_file;
- QList<QByteArray> m_lineList;
+ QByteArray m_file;
+ QByteArrayList m_lineList;
bool m_readOnly;
ReLogger* m_logger;
// true: the logger must be destroyed in the destructor
bool m_ownLogger;
+ bool m_modified;
};
#endif // RECONFIG_HPP
LOC_DELETE_TREE_3, // 11803
};
-#if defined __linux__ || defined WIN32
+#if defined __linux__ || defined _WIN32
void* memichr(void* heap, int cc, size_t length) {
const char* heap2 = reinterpret_cast<const char*>(heap);
int cc2 = tolower(cc);
}
return rc;
}
-
+#endif /* __linux__ */
+#if defined __linux__
int memicmp(const void* str1, const void* str2, size_t length) {
const char* str12 = reinterpret_cast<const char*>(str1);
const char* str22 = reinterpret_cast<const char*>(str2);
}
return rc;
}
-#endif /* __linux__ */
-
+#endif
/**
* Constructor.
*/
*/
#include "base/rebase.hpp"
-
enum {
LOC_DELETE_TREE_1 = LOC_FIRST_OF(LOC_FILE_UTILS), // 12501
LOC_DELETE_TREE_2, // 12502
int length = strlen(path);
rc.reserve(length);
int minLength = 0;
-#ifdef __WIN32__
+#ifdef _WIN32
// UNC path, e.g. "\\server\share"?
if ((path[0] == OS_SEPARATOR || path[0] == OS_2nd_SEPARATOR)
&& (path[1] == OS_SEPARATOR || path[1] == OS_2nd_SEPARATOR)) {
ix--;
}
}
- return rc;
+ return rc;
+}
+
+/**
+ * Returns the list of root filesystems.
+ *
+ * Windows: the list of available drives
+ *
+ * @return the list of root directories
+ */
+QStringList ReFileUtils::findRootDirs()
+{
+ QStringList rc;
+#if defined __linux__
+ 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));
+ }
+#endif
+ return rc;
}
/**
QFileInfo info(path);
bool rc = info.exists();
if (rc){
- if (isFile != NULL)
- *isFile = true;
if (! info.isDir())
rc = 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';
+#elif defined _WIN32
+ return isalpha(path[0]) && path[1] == ':' && path[2] == '\\' && path[3] == '\0';
#endif
}
* <code>false</code>: error occurred
*/
bool ReFileUtils::makeDirWithParents(const char* path, ReLogger* logger) {
- const char* end;
- const char* start = path;
- bool rc = true;
- QByteArray dir;
- while (rc && (end = strchr(start, OS_SEPARATOR)) != NULL) {
- if (end == path) {
- start++;
- dir += OS_SEPARATOR;
- } else {
- dir.append(start, end - start);
- start = end + 1;
- rc = makeDir(dir.constData(), logger);
- dir += OS_SEPARATOR;
- }
- }
- if (rc && start[0] != '\0') {
- dir.append(start);
- rc = makeDir(dir.constData(), logger);
- }
- return rc;
+ 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;
+#if defined _WIN32
+ 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;
}
/**
* 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(ix + 1);
- break;
- }
- ix--;
- }
- if (ix >= 0)
- rc = filename.mid(0, ix + 1);
- return rc;
+/**
+ * Extracts the path of a full filename.
+ *
+ * @param filename the filename (with or without path)
+ * @return "": no path available<br>
+ * "/": filename = "/"<br>
+ * otherwise: the path of <code>filename</code> including
+ * trailing separator
+ */
+QByteArray ReFileUtils::parentOf(const char* filename) {
+ QByteArray rc;
+
+ int ix = strlen(filename) - 1;
+ while (ix >= 0) {
+ if (filename[ix] == '/' || filename[ix] == '\\') {
+ rc.append(filename, ix + 1);
+ break;
+ }
+ ix--;
+ }
+ return rc;
}
/**
"cannot change times (%d): $s", errno, filename);
rc = false;
}
-#elif defined __WIN32__
-#error "not implemented"
+#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;
+ }
#endif
return rc;
}
int rc;
#if defined __linux__
rc = fseeko(file, offset, whence);
-#elif defined __WIN32__
- rc = _fseek64(file, offset, whence);
+#elif defined _WIN32
+ rc = _fseeki64(file, offset, whence);
#endif
return rc;
}
int64_t rc;
#if defined __linux__
rc = ftello(file);
-#elif defined __WIN32__
- rc = _ftell64(file);
+#elif defined _WIN32
+ rc = _ftelli64(file);
#endif
return rc;
}
QByteArray temp("/tmp");
static const char* firstVar = "TMP";
static const char* secondVar = "TEMP";
-#elif defined WIN32
+#elif defined _WIN32
QByteArray temp("c:\\temp");
static const char* firstVar = "TEMP";
static const char* secondVar = "TMP";
temp = ptr;
else if ((ptr = getenv(secondVar)) != NULL)
temp = ptr;
-#if defined WIN32
+#if defined _WIN32
temp.replace('\\', '/');
#endif
if (temp.at(temp.length() - 1) != '/')
static QString cleanPath(const QString& path);
static QString extensionOf(const QString& filename);
static QByteArray extensionOf(const char* filename);
+ static QStringList findRootDirs();
static bool isAbsolutPath(const QString& path);
static bool isAbsolutPath(const char* path);
static bool isDirectory(const QString& path, bool* isFile = NULL);
static QString nodeOf(const QString& filename);
static QByteArray nodeOf(const char* filename);
static QString parentOf(const QString& filename);
+ static QByteArray parentOf(const char* filename);
static QString pathAppend(const QString& base, const QString& path);
static QByteArray pathAppend(const char* base, const char* path);
static QByteArray& readFromFile(const char* filename, QByteArray& buffer);
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));
rc ^= buffer;
close(fh);
#endif
- return rc;
+ return rc;
+}
+
+/**
+ * Returns a unique identifier.
+ *
+ * @param readable <code>true</code>: the string is divided with '-' (every 4 chars)
+ * @return a BASE64 encoded near true random value (96 bit)
+ */
+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 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,
static void hash(const QByteArray& text, QByteArray& seed);
static seed_t pseudoTrueRandom();
static seed_t nearTrueRandom();
+ static QByteArray buildUUID(bool readable = true);
protected:
QByteArray m_name;
int m_counter;
const char ReStringUtils::AUTO_SEPARATOR = '\0';
const QByteArray ReStringUtils::m_empty;
+static const char* m_base64Chars =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+
+/**
+ * Transforms a BASE64 string into a byte array.
+ *
+ * @param input the string to decode
+ * @param inputLength the length of the string to decode. If -1 strlen() will be taken
+ * @param output OUT: the decoded bytes
+ * @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;
+ }
+ return output;
+}
+
+/**
+ * Transforms a byte array into a BASE64 string.
+ *
+ * @param input the byte array to encode
+ * @param inputLength the length of the byte array to encode
+ * @param output OUT: the encoded string
+ * @return <code>output</code> (for chaining)
+ */
+QByteArray& ReStringUtils::base64Encode(uint8_t const* input, size_t inputLength, QByteArray& 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;
+ }
+ 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++ = '=';
+ }
+ return output;
+}
/**
* Removes a given character from the end of the string if it is there.
}
static char s_fileSeparator = 0;
+
/**
* @brief Returns the os specific file path separator.
* @return the file path separator, e.g. "/" for linux
* More info: http://unlicense.org
* The latest sources: https://github.com/republib
*/
-#ifndef RPLSTRING_HPP
-#define RPLSTRING_HPP
+#ifndef RESTRING_HPP
+#define RESTRING_HPP
#ifdef __linux__
#define strnicmp(trg, src, len) strncasecmp(trg, src, len)
class ReStringUtils {
public:
+ static QByteArray& base64Decode(const char *input, int inputLength, QByteArray& output);
+ static QByteArray& base64Encode(const uint8_t *input, size_t inputLength, QByteArray& output);
static QByteArray& chomp(QByteArray &string, char cc = '\n');
static int countChar(const char* line, char cc);
static int count(const char* source, const char* item);
static const char AUTO_SEPARATOR;
};
-#endif // RPLSTRING_HPP
+#endif // RESTRING_HPP
void ReTest::ensureNotExist(const char* fullname)
{
if (exists(fullname))
- unlink(fullname);
+ _unlink(fullname);
if (exists(fullname) && exists(fullname, true))
- rmdir(fullname);
+ _rmdir(fullname);
if (exists(fullname))
error("cannot delete (%d): %s", errno, fullname);
}
if (parent != NULL) {
temp += parent;
if (stat(temp.constData(), &info) != 0)
- mkdir(temp.constData(), (-1));
+ _mkdir(temp.constData());
temp += sep;
}
if (node != NULL) {
temp += node;
temp += sep;
if (stat(temp.data(), &info) != 0)
- mkdir(temp.data(), -1);
+ _mkdir(temp.data());
}
if (!withSeparator)
temp.resize(temp.length() - 1);
rc += node;
struct stat info;
if (deleteIfExists && stat(rc.constData(), &info) == 0)
- unlink(rc.constData());
+ _unlink(rc.constData());
return rc;
}
/**
#include <unistd.h>
#include <sys/time.h>
#include <fcntl.h>
-#else
+#elif defined _WIN32
#include <io.h>
#include <direct.h>
+#include <sys/utime.h>
#endif
+
#include <QThread>
#include <QIODevice>
#include <QTextStream>
typedef qreal real_t;
typedef QString ReString;
#define RE_UNUSED(x) (void)(x)
-
+#ifdef _WIN32
+typedef quint64 uint64_t;
+typedef short int int16_t;
+#endif
#ifdef __linux__
#define _strcasecmp strcasecmp
#define OS_SEPARATOR '/'
#define _unlink unlink
//typedef qint64 uint64_t;
#else
+#define S_ISDIR(mode) (((mode) & _S_IFDIR) != 0)
#define _strcasecmp _stricmp
#define OS_SEPARATOR '\\'
#define OS_SEPARATOR_STR "\\"
#endif
checkEqu(owner, p1.m_user);
checkEqu(group, p1.m_group);
+#ifdef __linux__
checkEqu( S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IROTH, p1.m_fileMode);
checkEqu(S_IWUSR | S_IRUSR | S_IXUSR | S_IWGRP | S_IRGRP
| S_IXGRP | S_IROTH | S_IXOTH | __S_IFDIR, p1.m_dirMode);
+#endif
ReOSPermissions p2(p1);
checkEqu(owner, p2.m_user);
checkEqu(group, p2.m_group);
- checkEqu( S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IROTH, p2.m_fileMode);
+#ifdef __linux__
+ checkEqu( S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IROTH, p2.m_fileMode);
checkEqu(S_IWUSR | S_IRUSR | S_IXUSR | S_IWGRP | S_IRGRP
| S_IXGRP | S_IROTH | S_IXOTH | __S_IFDIR, p2.m_dirMode);
+#endif
p2.m_user = 0x4711;
p2.m_group = 0x1147;
p2.m_dirMode = 123;
ReFileUtils::tempDirEmpty("subdir2", "cuReFileUtils", true));
QByteArray subdir(dir);
subdir.append("subdirX");
- mkdir(subdir.constData(), ALLPERMS);
+ _mkdir(subdir.constData());
struct stat info;
checkEqu(0, stat(subdir.constData(), &info));
ReFileUtils::tempDirEmpty("subdir2", "cuReFileUtils", true);
QByteArray base = ReFileUtils::tempDir("ReFileUtils");
for (char cc = 'a'; cc < 'f'; cc++) {
QByteArray subdir(base + cc);
- mkdir(subdir.constData(), ALLPERMS);
+ _mkdir(subdir.constData());
for (char cc2 = '1'; cc2 < '5'; cc2++) {
QByteArray name(subdir);
name.append(OS_SEPARATOR_STR).append(&cc2, 1);
ReFileUtils::writeToFile(name, name);
name += "dir";
- mkdir(name.constData(), ALLPERMS);
+ _mkdir(name.constData());
name.append(OS_SEPARATOR_STR).append("x.txt");
ReFileUtils::writeToFile(name, name);
}
// the dir must exist:
checkEqu(0, stat(base, &info));
// rmdir() works only if the dir is empty:
- checkEqu(0, rmdir(base));
+ checkEqu(0, _rmdir(base));
buildTree();
checkT(ReFileUtils::deleteTree(QString(base), false, &m_logger));
checkEqu(0, stat(base, &info));
QByteArray id = ReProcess::executeAndRead(QString("/usr/bin/id"), args);
checkF(id.isEmpty());
+#elif defined _WIN32
+ QStringList args;
+ args.append("/c");
+ args.append("dir");
+ args.append("c:\\");
+ QByteArray id = ReProcess::executeAndRead(QString("cmd"), args);
+ checkF(id.isEmpty());
#else
#error "missing test"
#endif
QString ReGuiApplication::buildHomeDir(QString homeDirBase, const QString& node){
QString homeDir;
if (homeDirBase.isEmpty()){
- homeDir = QDir::home().absoluteFilePath(node);
+ homeDir = ReFileUtils::nativePath(QDir::home().absoluteFilePath(node));
} else if (ReFileUtils::isRootDir(homeDirBase.toLatin1().constData())){
homeDir = homeDirBase + node;
}
#ifdef __linux__
m_uid(geteuid()),
m_gid(getegid()),
+#else
+ m_uid(0),
+ m_gid(0),
#endif
m_writeable(false),
m_logger(logger),
static ReFileSystem* buildFromUrl(const QString& url);
protected:
QString m_name;
-#ifdef __linux__
int m_uid;
int m_gid;
-#endif
// ending with OS_SEPARATOR:
QString m_directory;
// All links are replaced by its targets:
#include <dirent.h>
#include <grp.h>
#include <pwd.h>
-#elif defined __WIN32__
+#elif defined _WIN32
#include <tchar.h>
#include "windows.h"
#include <winnt.h>
#if defined __linux__
typedef struct timespec ReFileTime_t;
typedef __off_t ReFileSize_t;
-#elif defined __WIN32__
+#elif defined _WIN32
typedef FILETIME ReFileTime_t;
typedef int64_t ReFileSize_t;
+typedef unsigned short mode_t;
#endif
/** Returns whether a time is greater (younger) than another.
* @param time1 first operand