From: hama
Date: Mon, 11 Apr 2016 22:52:57 +0000 (+0200)
Subject: v2016.04.07, rebackgui, warnings found by clang
X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=5536e688dc40648660b55c6b1918512eb8b00c41;p=reqt
v2016.04.07, rebackgui, warnings found by clang
rebackgui:
* test of symbolic link before test of directory
* allows being root by setuid()
* translation improvements
* documentation in rebackgui.html
lib:
* file copy under linux:
** copying symbolic links
** setting owner and group
* linux: using QT setpermissions() instead of chmod()
* new: modifyToNonExisting()
* ReLogger(): correction of logging file "ring" (incrementing numbers,
limited count of files)
* ReProcess::executeAndRead(): timeout
* added: I18N::b2s()
* more tests
* uint64_t changed to quint64
* ReGuiApplication(): default base dir is now /.reappl
---
diff --git a/PrepTmp.sh b/PrepTmp.sh
new file mode 100755
index 0000000..dd555f5
--- /dev/null
+++ b/PrepTmp.sh
@@ -0,0 +1,8 @@
+#! /bin/bash
+
+mkdir /tmp/trg
+mkdir /tmp/src
+cp -a /home/bin/std/*.py /tmp/src
+mkdir /tmp/src/x
+cp -a /home/bin/std/a*.pl /tmp/src/x
+
diff --git a/RenTmp.sh b/RenTmp.sh
new file mode 100755
index 0000000..8259916
--- /dev/null
+++ b/RenTmp.sh
@@ -0,0 +1,4 @@
+#! /bin/bash
+cp -a /tmp/src /tmp/trg
+rename "s/py/px/g" /tmp/trg/src/*
+touch /tmp/trg/src/*
diff --git a/appl/rebackgui/BackupEngine.cpp b/appl/rebackgui/BackupEngine.cpp
index 9e9a138..d2345a8 100644
--- a/appl/rebackgui/BackupEngine.cpp
+++ b/appl/rebackgui/BackupEngine.cpp
@@ -157,15 +157,15 @@ void BackupTask::copyFile(int index, const QString& relPath,
if (! ReFileUtils::makeDirWithParents(targetDir))
error(QObject::tr("cannot make directory (%1): %2").arg(errno).arg(targetDir));
}
- QFileInfo info(source);
+ QFileInfo sourceInfo(source);
if (m_verboseLevel >= VerboseStandard)
- m_mainWindow->addToFileList(source + " " + ReQStringUtils::readableSize(info.size()));
+ m_mainWindow->addToFileList(source + " " + ReQStringUtils::readableSize(sourceInfo.size()));
m_mutex.lock();
m_processedFiles++;
- m_processedBytes += info.size();
+ m_processedBytes += sourceInfo.size();
m_mutex.unlock();
- QString errorMsg = ReFileUtils::copy(source, target, &info, m_buffer);
+ QString errorMsg = ReFileUtils::copy(source, target, &sourceInfo, m_buffer);
if (! errorMsg.isEmpty()){
error(errorMsg);
if (m_verboseLevel >= VerboseStandard)
@@ -645,7 +645,8 @@ void SearchTask::searchOneDirectory(const QString& source,
}
it.next();
node = it.fileName();
- if (it.fileInfo().isDir()){
+ QFileInfo fileInfo = it.fileInfo();
+ if (! fileInfo.isSymLink() && fileInfo.isDir()){
// nothing to do
} else if (! m_fileMatcher.matches(node)){
m_mutex.lock();
@@ -666,7 +667,7 @@ void SearchTask::searchOneDirectory(const QString& source,
const QFileInfo src = it.fileInfo();
if (trg.size() != src.size())
doTransfer = true;
- else if ((diff = abs(src.lastModified().toMSecsSinceEpoch()
+ else if ((diff = _abs(src.lastModified().toMSecsSinceEpoch()
- trg.lastModified().toMSecsSinceEpoch())) >= 2000)
doTransfer = true;
}
@@ -694,8 +695,9 @@ void SearchTask::searchOneDirectory(const QString& source,
break;
}
it2.next();
-
- if (it2.fileInfo().isDir() && (node = it2.fileName()) != "." && node != ".."
+ QFileInfo fileInfo = it2.fileInfo();
+ if (! fileInfo.isSymLink() && fileInfo.isDir()
+ && (node = it2.fileName()) != "." && node != ".."
&& m_dirMatcher.matches(node)){
if (target.isEmpty())
subTarget.clear();
@@ -753,7 +755,8 @@ bool SearchTargetTask::removeOlder(const QString& directory, const QDateTime& ti
}
it.next();
node = it.fileName();
- if (it.fileInfo().isDir()){
+ QFileInfo fileInfo = it.fileInfo();
+ if (! fileInfo.isSymLink() && fileInfo.isDir()){
if (node != "." && node != ".."){
if (! removeOlder(ReFileUtils::nativePath(it.filePath()), time))
isEmpty = false;
@@ -820,7 +823,8 @@ void SearchTargetTask::searchOneDirectory(const QString& target,
}
it.next();
node = it.fileName();
- if (it.fileInfo().isDir()){
+ QFileInfo fileInfo = it.fileInfo();
+ if (! fileInfo.isSymLink() && fileInfo.isDir()){
// nothing to do
} else{
Command command = CmdUndef;
@@ -857,12 +861,13 @@ void SearchTargetTask::searchOneDirectory(const QString& target,
if (m_shouldStop){
break;
}
- it2.next();
-
- if (it2.fileInfo().isDir() && (node = it2.fileName()) != "." && node != ".."){
+ it2.next();
+ QFileInfo fileInfo = it2.fileInfo();
+ if (! fileInfo.isSymLink() && fileInfo.isDir()
+ && (node = it2.fileName()) != "." && node != ".."){
QString newSource = source + it2.fileName();
QFileInfo src(newSource);
- if (src.exists() && src.isDir())
+ if (src.exists() && ! src.isSymLink() && src.isDir())
searchOneDirectory(ReFileUtils::nativePath(it2.filePath()),
newSource + OS_SEPARATOR_STR, index);
else{
@@ -883,6 +888,25 @@ void SearchTargetTask::searchOneDirectory(const QString& target,
void SearchTargetTask::moveToShadow(const QString& target, const QString& relPath, int index){
QString shadowDir = m_shadowDirs.at(index) + relPath;
ReQStringUtils::chomp(shadowDir, OS_SEPARATOR);
+ if (ReFileUtils::isDirectory(shadowDir)){
+ QString targetName = shadowDir;
+ int pos = targetName.length() / 2;
+ while(pos < shadowDir.length()){
+ char cc = '0' - 1;
+ do{
+ targetName[pos] = ++cc;
+ } while (cc <= 'Z' && QFileInfo(targetName).exists());
+ if (cc <= 'Z'){
+ if (rename(I18N::s2b(shadowDir).constData(),
+ I18N::s2b(targetName).constData()) != 0)
+ error(QObject::tr("kann Schattenverzeichnis nicht umbenennen: %1 -> %2")
+ .arg(shadowDir, targetName));
+ else break;
+ }
+ pos++;
+ }
+
+ }
if (! ReFileUtils::makeDirWithParents(shadowDir)){
error(QObject::tr("cannot create shadow directory (%1): %2")
diff --git a/appl/rebackgui/main.cpp b/appl/rebackgui/main.cpp
index df7047f..2c2fcde 100644
--- a/appl/rebackgui/main.cpp
+++ b/appl/rebackgui/main.cpp
@@ -15,10 +15,11 @@
#include
char** g_argv;
int main(int argc, char* argv[]) {
- g_argv = argv;
- QString homeDir = argc > 1 ? argv[1] : "";
- QApplication a(argc, argv);
- MainWindow w(a, homeDir);
- w.show();
- return a.exec();
+ g_argv = argv;
+ QString homeDir = argc > 1 ? argv[1] : "";
+ QApplication::setSetuidAllowed(true);
+ QApplication a(argc, argv);
+ MainWindow w(a, homeDir);
+ w.show();
+ return a.exec();
}
diff --git a/appl/rebackgui/mainwindow.cpp b/appl/rebackgui/mainwindow.cpp
index c430ab9..e4cbb7c 100644
--- a/appl/rebackgui/mainwindow.cpp
+++ b/appl/rebackgui/mainwindow.cpp
@@ -13,7 +13,7 @@
#include "aboutdialog.hpp"
#include
-const QString VERSION("2016.02.24");
+const QString VERSION("2016.04.07");
/**
* Constructor.
@@ -23,7 +23,7 @@ const QString VERSION("2016.02.24");
*/
MainWindow::MainWindow(QApplication& application, const QString& homeDir,
QWidget *parent) :
- ReGuiApplication(application, "rebackgui", homeDir, 2, 100100100, "de", parent),
+ ReGuiApplication(application, "rebackgui", homeDir, 2, 10100100, "de", parent),
ReGuiValidator(),
ui(new Ui::MainWindow),
m_configuration(this),
diff --git a/appl/rebackgui/mainwindow.ui b/appl/rebackgui/mainwindow.ui
index f556cc3..8fb4ae9 100644
--- a/appl/rebackgui/mainwindow.ui
+++ b/appl/rebackgui/mainwindow.ui
@@ -197,7 +197,7 @@
-
+
@@ -785,12 +785,12 @@
00839
- 26
+ 29
- File
+ Fi&le
@@ -801,12 +801,12 @@
- Edit
+ Edi&t
- Help
+ Hel&p
@@ -815,7 +815,7 @@
- Action
+ A&ction
@@ -838,37 +838,37 @@
- Load Config
+ &Load Config
- Save Config
+ &Save Config
- Exit
+ &Exit
- Start backup
+ &Start backup
- Stop
+ St&op
- About
+ &About
- Checksums
+ &ChecksumsCalculates checksums for source and target files and reports differences
@@ -876,7 +876,7 @@
- Clean
+ C&lean
@@ -884,7 +884,7 @@
true
- English
+ &English
@@ -892,7 +892,7 @@
true
- German
+ &German
@@ -900,7 +900,7 @@
true
- Autosave
+ &Autosave
diff --git a/appl/rebackgui/rebackgui.de.qm b/appl/rebackgui/rebackgui.de.qm
new file mode 100644
index 0000000..ca4ccf5
Binary files /dev/null and b/appl/rebackgui/rebackgui.de.qm differ
diff --git a/appl/rebackgui/rebackgui.de.ts b/appl/rebackgui/rebackgui.de.ts
index e1adf8b..b8a17ec 100644
--- a/appl/rebackgui/rebackgui.de.ts
+++ b/appl/rebackgui/rebackgui.de.ts
@@ -106,7 +106,6 @@ p, li { white-space: pre-wrap; }
- Aktion
@@ -205,7 +204,6 @@ p, li { white-space: pre-wrap; }
- Beenden
@@ -217,7 +215,6 @@ p, li { white-space: pre-wrap; }
- Prüfsummen
@@ -228,7 +225,6 @@ p, li { white-space: pre-wrap; }
- Protokoll:Bereinigen
@@ -272,7 +268,6 @@ p, li { white-space: pre-wrap; }
- Autom. Speichern
@@ -356,81 +351,91 @@ p, li { white-space: pre-wrap; }
-
+
+ FileBearbeiten
- Datei
+ Datei
-
- Bearbeiten
+
+ Edit
+ Bearbeiten
-
- Hilfe
+
+ Help
+ Hilfe
-
- Konfiguration laden
+
+ Load Config
+ Konfiguration laden
-
- Konfiguration sichern
+
+ Save Config
+ Konfiguration sichern
-
- Beenden
+
+ Exit
+ Beenden
-
- Sicherung starten
+
+ Start backup
+ Sicherung starten
-
- Ãber
+
+ About
+ Ãber
-
-
+
+ English
+
-
-
+
+ German
+
-
-
-
+
+
+ Kein Sicherungselement ausgewählt
-
-
-
+
+
+ Ziel nicht vorhanden
-
+ Quellverzeichnis auswählen
-
+ Zielverzeichnis auswählen
-
+ Ziel mit %1 vorbelegt
@@ -519,17 +524,22 @@ p, li { white-space: pre-wrap; }
Suche beendet: zu behandeln: %1 mit %2 passend: %3 gesamt: %4 Unterverz: %5 Laufzeit: %6
-
+
+
+
+
+
+ Kann Schattenverzeichnis nicht erstellen (%1): %2
-
+ Kann Datei nicht in Schattenverzeichnis verschieben (%1): %2 -> %3
-
+ Suche im Ziel bendet: zu behandeln: %1 mit %2 zu löschende Verzeichnisse: %3 gesamt: %4 Unterverz.: %5 Laufzeit: %6
@@ -540,9 +550,9 @@ p, li { white-space: pre-wrap; }
-
-
-
+
+
+ Kann nicht öffnen (%1): %2
@@ -552,33 +562,33 @@ p, li { white-space: pre-wrap; }
Unbekanntes Format in %1-%2: %3
-
+ Kann nicht schreiben (%1): %2
-
+ configuration changed: %1Konfiguration gespeichert: %1
-
+ Suche gestartet...
-
+ Ja
-
+ nein
-
+ Nicht gefunden: %1
@@ -587,32 +597,37 @@ p, li { white-space: pre-wrap; }
Kann nicht schreiben(%1): %2 [%3/%4]
-
+
+
+
+
+
+ Kann nicht schreiben(%1): %2 [%3/%4]
-
+ Datei kann nur teilweise gelesen werden: %1 [%2/%3]
-
+ Kann Datum/Zeit nicht setzen (%1): %2
-
+ Kann Dateirechte nicht setzen (%1): %2
-
+ Kann Verzeichnis nicht erzeugen (%1): %2
-
+ Kann Verzeichnis nicht erzeugen (ist eine Datei):
diff --git a/appl/rebackgui/rebackgui.html b/appl/rebackgui/rebackgui.html
new file mode 100644
index 0000000..8ca4bc0
--- /dev/null
+++ b/appl/rebackgui/rebackgui.html
@@ -0,0 +1,73 @@
+
+
+
+
+
Documentation of rebackgui
+
Release Notes
+
+
+
v2016.04.06
+
Basic version
+
+
+
+
+
+
User Manual
+
Purpose:
+
This program makes backups.
+
+
Usage
+
hmbackgui [<home_dir>]
+<home_dir>:
+ the base directory for the configuration directory ".reappl"
+ Default: the home directory of the user
+
+
Example:
+
hmbackgui /home/hugo
+
+
+
Installation
+
Linux
+
+
Copy rebackgui to /usr/local/bin
+
Copy rebackgui.*.qm to the configuration directory, e.g. /home/hm/.reappl
+
+
cd /usr/local/bin
+chown root.root rebackgui
+chmod u+s rebackgui
+
+
+
+
Configuration
+
The configuration is stored in <home_dir>/.rebackgui/rebackgui.conf
+
+
+
Program Documentation
+
+
Programming Features
+
+
This is a example for a complete QT application with the following features:
+
+
multithreaded
+
pattern matching
+
multithreaded GUI building
+
+
+
+
(Un)License: Public Domain
+
+
You can use and modify this file without any restriction.
+Do what you want.
+No warranties and disclaimer of any damages.
+More info: http://unlicense.org
+The latest sources: https://github.com/republib.
+
+
+
+
diff --git a/appl/rebackgui/rebackgui.pro b/appl/rebackgui/rebackgui.pro
index 4b10c3d..ba86e1c 100644
--- a/appl/rebackgui/rebackgui.pro
+++ b/appl/rebackgui/rebackgui.pro
@@ -53,7 +53,8 @@ FORMS += mainwindow.ui \
DISTFILES += \
ReBackGui.html \
- osconnect.pl
+ osconnect.pl \
+ rebackgui.html
TRANSLATIONS = rebackgui.de.ts
CODECFORTR = UTF-8
diff --git a/appl/recommand/recommand.pro b/appl/recommand/recommand.pro
index 8efbe4f..318b324 100644
--- a/appl/recommand/recommand.pro
+++ b/appl/recommand/recommand.pro
@@ -29,7 +29,8 @@ SOURCES += main.cpp\
../../gui/ReGuiQueue.cpp \
../../gui/ReGuiUtils.cpp \
mainwindow.cpp \
- CommandProcessor.cpp
+ CommandProcessor.cpp \
+ ../../base/ReProcess.cpp
HEADERS += mainwindow.hpp \
CommandProcessor.hpp \
diff --git a/base/ReConfig.hpp b/base/ReConfig.hpp
index 617e566..b2bdb44 100644
--- a/base/ReConfig.hpp
+++ b/base/ReConfig.hpp
@@ -11,7 +11,7 @@
#ifndef RECONFIG_HPP
#define RECONFIG_HPP
-class ReConfig: public ReConfigurator, protected QHash {
+class ReConfig: public ReConfigurator, public QHash {
public:
ReConfig(const char* file = NULL, bool readOnly = true, ReLogger* logger =
NULL);
diff --git a/base/ReContainer.cpp b/base/ReContainer.cpp
index 62d7683..9f50f2d 100644
--- a/base/ReContainer.cpp
+++ b/base/ReContainer.cpp
@@ -67,12 +67,12 @@ const char* ReContainer::MAGIC_1 = "Rpl&1";
* @param sizeHint Probable length of the container
*/
ReContainer::ReContainer(size_t sizeHint) :
- m_data(""),
- m_countBags(0),
- m_typeList(""),
- m_ixItem(0),
- m_ixBag(0),
- m_readPosition(NULL) {
+ m_data(""),
+ m_countBags(0),
+ m_typeList(""),
+ m_ixItem(0),
+ m_ixBag(0),
+ m_readPosition(NULL) {
if (sizeHint > 0)
m_data.reserve(sizeHint);
}
@@ -188,10 +188,10 @@ const QByteArray& ReContainer::getData() {
char buffer[128];
// RPL&1 0a b5[2]cis: !12
qsnprintf(buffer, sizeof buffer, "%x[%d]%s:",
- (unsigned int) m_data.length(), m_countBags, m_typeList.data());
+ (unsigned int) m_data.length(), m_countBags, m_typeList.data());
char header[128 + 8];
qsnprintf(header, sizeof header, "%s%02x%s", MAGIC_1,
- (unsigned int) strlen(buffer), buffer);
+ (unsigned int) strlen(buffer), buffer);
m_data.insert(0, header);
}
return m_data;
@@ -207,25 +207,25 @@ void ReContainer::fill(const QByteArray& data) {
const char* ptr = m_data.data();
if (strncmp(ptr, MAGIC_1, strlen(MAGIC_1)) != 0)
throw RplInvalidDataException(LOG_ERROR, LOC_FILL_1,
- "container has no magic", data.data(), data.length());
+ "container has no magic", data.data(), data.length());
ptr += strlen(MAGIC_1);
unsigned int headerSize = 0;
if (sscanf(ptr, "%02x", &headerSize) != 1)
throw RplInvalidDataException(LOG_ERROR, LOC_FILL_2,
- "container has no header size", ptr, 2);
+ "container has no header size", ptr, 2);
ptr += 2;
unsigned int dataSize = 0;
unsigned int countBags = 0;
if (sscanf(ptr, "%x[%x]", &dataSize, &countBags) != 2)
throw RplInvalidDataException(LOG_ERROR, LOC_FILL_2,
- "container has no data_size[bag_count]", ptr, 16);
+ "container has no data_size[bag_count]", ptr, 16);
m_countBags = countBags;
ptr = strchr(ptr, ']') + 1;
const char* end = ptr + strspn(ptr, "cisdDX!");
if (end == ptr || *end != ':') {
throw RplInvalidDataException(LOG_ERROR, LOC_FILL_2,
- "container has no valid typelist", ptr, 16);
+ "container has no valid typelist", ptr, 16);
}
m_typeList.clear();
m_typeList.append(ptr, end - ptr);
@@ -247,13 +247,13 @@ int ReContainer::getCountBags() const {
void ReContainer::nextBag() {
if (m_ixItem < m_typeList.length() && m_ixItem != -1)
throw ReException(LOG_ERROR, LOC_NEXT_BAG_1, NULL,
- "end of bag not reached: remaining items: %s",
- m_typeList.data() + m_ixItem);
+ "end of bag not reached: remaining items: %s",
+ m_typeList.data() + m_ixItem);
m_ixItem = 0;
m_ixBag++;
if (m_ixBag >= m_countBags)
throw ReException(LOG_ERROR, LOC_NEXT_BAG_2, NULL, "no more bags: %d",
- m_ixBag);
+ m_ixBag);
}
/**
* @brief Sets the next item.
@@ -267,20 +267,20 @@ void ReContainer::nextItem(type_tag_t expected) {
}
if (m_ixItem >= m_typeList.length())
throw ReException(LOG_ERROR, LOC_NEXT_ITEM_1, ReLogger::globalLogger(),
- "no more items in the bag");
+ "no more items in the bag");
type_tag_t current = (type_tag_t) m_typeList.at(m_ixItem);
// Unify all data types:
if (current == TAG_DATA4G || current == TAG_DATA64K)
current = TAG_DATA255;
if (current != expected)
throw ReException(LOG_ERROR, LOC_NEXT_ITEM_2, NULL,
- "current item is a %c, not a %c", (char) m_typeList.at(m_ixItem),
- (char) expected);
+ "current item is a %c, not a %c", (char) m_typeList.at(m_ixItem),
+ (char) expected);
m_ixItem++;
if (m_readPosition > (uint8_t*) (m_data.data() + m_data.length()))
throw ReException(LOG_ERROR, LOC_NEXT_ITEM_3, NULL,
- "container size too small. Bag: %d of %d Item: %d of %d",
- 1 + m_ixBag, m_countBags, 1 + m_ixItem, m_typeList.length());
+ "container size too small. Bag: %d of %d Item: %d of %d",
+ 1 + m_ixBag, m_countBags, 1 + m_ixItem, m_typeList.length());
}
/**
@@ -307,7 +307,7 @@ int ReContainer::nextInt() {
unsigned int value = 0;
if (sscanf((const char*) m_readPosition, "%x ", &value) != 1)
throw RplInvalidDataException(LOG_ERROR, LOC_NEXT_INT_1,
- "not a hex_number", m_readPosition, 16);
+ "not a hex_number", m_readPosition, 16);
m_readPosition = (uint8_t*) strchr((const char*) m_readPosition, ' ') + 1;
if (isNegativ)
value = -value;
@@ -323,10 +323,10 @@ int64_t ReContainer::nextInt64() {
bool isNegativ = *m_readPosition == '-';
if (isNegativ)
m_readPosition++;
- uint64_t value = 0;
+ quint64 value = 0;
if (sscanf((const char*) m_readPosition, "%llx ", &value) != 1)
throw RplInvalidDataException(LOG_ERROR, LOC_NEXT_INT_1,
- "not a hex_number", m_readPosition, 16);
+ "not a hex_number", m_readPosition, 16);
m_readPosition = (uint8_t*) strchr((const char*) m_readPosition, ' ') + 1;
if (isNegativ)
value = -value;
@@ -392,7 +392,7 @@ size_t ReContainer::nextData(QByteArray& data, bool append) {
* @return a human readable string describing the container
*/
QByteArray ReContainer::dump(const char* title, int maxBags,
- int maxStringLength, int maxBlobLength, char separatorItems) {
+ int maxStringLength, int maxBlobLength, char separatorItems) {
QByteArray rc;
rc.reserve(64000);
rc.append("=== ").append(title).append('\n');
@@ -409,7 +409,7 @@ QByteArray ReContainer::dump(const char* title, int maxBags,
maxBags = m_countBags;
for (int ixBag = 0; ixBag < maxBags; ixBag++) {
rc.append("--- bag ").append(ReStringUtils::toNumber(ixBag)).append(
- ":\n");
+ ":\n");
nextBag();
QByteArray item;
int maxLength;
@@ -422,9 +422,9 @@ QByteArray ReContainer::dump(const char* title, int maxBags,
case TAG_INT:
iValue = nextInt();
rc.append(" i: ").append(ReStringUtils::toNumber(iValue)).append(
- " / ");
+ " / ");
rc.append(ReStringUtils::toNumber(iValue, "%x")).append(
- separatorItems);
+ separatorItems);
break;
case TAG_STRING:
sValue = nextString();
@@ -439,10 +439,10 @@ QByteArray ReContainer::dump(const char* title, int maxBags,
rc.append(' ').append((char) currentType).append(": [");
rc.append(ReStringUtils::toNumber(item.length())).append("] ");
maxLength =
- item.length() < maxBlobLength ?
- item.length() : maxBlobLength;
+ item.length() < maxBlobLength ?
+ item.length() : maxBlobLength;
rc.append(ReStringUtils::hexDump(item.data(), maxLength, 16))
- .append(separatorItems);
+ .append(separatorItems);
break;
default:
break;
diff --git a/base/ReFileUtils.cpp b/base/ReFileUtils.cpp
index 0897aa8..6f9b56f 100644
--- a/base/ReFileUtils.cpp
+++ b/base/ReFileUtils.cpp
@@ -21,6 +21,7 @@ enum {
LOC_MAKE_DIR_2, // 12506
LOC_SET_TIMES_2, // 12507
};
+int ReFileUtils::m_maxCharSet = 128;
QDateTime ReFileUtils::m_undefinedTime;
@@ -161,11 +162,13 @@ QString ReFileUtils::cleanPath(const QString& path) {
* @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
+ * @param buffer IN/OUT: used for buffering the file content
+ *
* @return
*/
QString ReFileUtils::copy(const QString& source, const QString& target,
- const QFileInfo* sourceInfo, QByteArray& buffer){
+ const QFileInfo* sourceInfo, QByteArray& buffer,
+ bool setUser){
QString rc;
#if defined _WIN32
const ushort* src = source.utf16();
@@ -182,9 +185,23 @@ QString ReFileUtils::copy(const QString& source, const QString& target,
sourceInfo2.setFile(source);
sourceInfo = &sourceInfo2;
}
- if (! sourceInfo->exists())
+ if (! sourceInfo->exists()){
rc = QObject::tr("not found: %1").arg(source);
- else {
+ } else if (sourceInfo->isSymLink()){
+ // sourceInfo->symLink() returns the absolute path for relative links too.
+ // Though we use readlink():
+ size_t size = buffer.capacity();
+ if (size < 4096){
+ buffer.resize(4096);
+ size = buffer.capacity();
+ }
+ int length = readlink(source2.constData(), buffer.data(), size);
+ buffer.resize(length);
+ QString link = I18N::s2b(buffer);
+ QFile::link(link, target);
+ } else if (! sourceInfo->isFile()){
+ rc = QObject::tr("not a regular file: %1").arg(source);
+ } else {
FILE* fpSource = fopen(source2.constData(), "rb");
if (fpSource == NULL){
rc = QObject::tr("cannot open (%1): %2").arg(errno).arg(source);
@@ -228,6 +245,15 @@ QString ReFileUtils::copy(const QString& source, const QString& target,
}
}
fclose(fpSource);
+#ifdef __linux__
+ if (setUser){
+ if (chown(target2.constData(), sourceInfo->ownerId(),
+ sourceInfo->groupId()) != 0 && rc.isEmpty()){
+ rc = QObject::tr("cannot set user/gid (%1): %2")
+ .arg(errno).arg(target);
+ }
+ }
+#endif
}
}
#endif
@@ -372,6 +398,73 @@ QStringList ReFileUtils::findRootDirs()
return rc;
}
+/**
+ * Modify a filename until the file does not exist.
+ *
+ * @param filename filename to modify
+ * @return "": no unused filename found
+ * otherwise: a modification of filename which does not exist
+ */
+QString ReFileUtils::modifyToNonExisting(const QString& path){
+ static const char* charSet = "$_-+=!^#%~01234567890abcdefghijklmnopqrstuvwxyz";
+ static int charSetLength = 0;
+ static char indexOf[128] = { 0 };
+ if (charSetLength == 0){
+ charSetLength = min(m_maxCharSet, strlen(charSet));
+ memset(indexOf, charSetLength, sizeof indexOf);
+ for (int ix = 0; ix < charSetLength; ix++){
+ indexOf[(int) charSet[ix]] = ix;
+ }
+ }
+ QString rc = path;
+ int ix;
+ // begin is the first index of the filename (without path)
+ int begin = 0;
+ // last is the last index of the filename (without extension)
+ int last = -1;
+ for (ix = rc.length() - 1; ix >= 0; ix--){
+ if (rc.at(ix) == OS_SEPARATOR || rc.at(ix) == OS_2nd_SEPARATOR){
+ begin = ix - 1;
+ if (last < 0)
+ last = rc.length() - 1;
+ break;
+ } else if (last < 0 && rc.at(ix) == '.')
+ last = ix + 1;
+ }
+ if (last <= 0)
+ last = rc.length() - 1;
+ // first is the index of the first modified character in the filename
+ int first = last + 1;
+ while (first <= begin && QFile(rc).exists()){
+ if (first < last){
+ first++;
+ rc[last] = charSet[0];
+ } else if ( (ix = indexOf[rc.at(last).unicode()]) < charSetLength - 1){
+ rc[last] = charSet[ix + 1];
+ } else {
+ int pos = last;
+ rc[last] = charSet[0];
+ while(true){
+ if (--pos < begin){
+ first = begin + 1;
+ rc = "";
+ break;
+ }
+ if (pos > first){
+ first++;
+ rc[first] = charSet[0];
+ break;
+ } else if ( (ix = indexOf[rc.at(pos).unicode()]) < charSetLength - 1){
+ rc[pos] = charSet[ix + 1];
+ break;
+ } else {
+ rc[pos] = charSet[0];
+ }
+ }
+ }
+ }
+ return rc;
+}
/**
* Returns whether a path is an absolute path.
*
@@ -413,14 +506,15 @@ bool ReFileUtils::isAbsolutPath(const char* path) {
*
* @param path full name of the directory to inspect
* @param isFile OUT: true: this is a file (and not a directory)
- * @return true: path is a directory
+ * @return true: path is a directory (and not a symbolic
+ * link)
*/
bool ReFileUtils::isDirectory(const QString& path, bool* isFile)
{
QFileInfo info(path);
bool rc = info.exists();
if (rc){
- if (! info.isDir())
+ if (info.isSymLink() || ! info.isDir())
rc = false;
if (isFile != NULL)
*isFile = ! rc;
@@ -776,72 +870,6 @@ QByteArray ReFileUtils::replaceExtension(const char* path, const char* ext) {
return rc;
}
-/**
- * Splits an URL into its parts.
- *
- * Examples:
- *