]> gitweb.hamatoma.de Git - reqt/commitdiff
some methods moved from ReQStringUtils to ReFileUtils
authorhama <hama@siduction.net>
Sun, 27 Sep 2015 09:10:43 +0000 (11:10 +0200)
committerhama <hama@siduction.net>
Sun, 27 Sep 2015 09:10:43 +0000 (11:10 +0200)
base/ReFileUtils.cpp
base/ReFileUtils.hpp
base/ReQStringUtils.cpp
base/ReQStringUtils.hpp
cunit/cuReFileSystem.cpp
cunit/cuReFileUtils.cpp
cunit/cuReQStringUtils.cpp
os/ReFileSystem.cpp
os/ReFileSystem.hpp

index 314d22be111e3c4f90234eb8e1634e5de17c0435..1f86781a2b36db3041345ae21a15ff9155e22e4e 100644 (file)
@@ -29,6 +29,47 @@ ReTreeStatistic::ReTreeStatistic() :
            m_fileSizes(0L) {
 }
 
+/**
+ * Appends a relative path to base directory name (absolute or relative).
+ *
+ * @param base the base directory, relative or absolute
+ * @param path a relative path (relative to <code>base</code>)
+ * @return      <code>path</code> if it is an absolute path<br>
+ *                             otherwise: the combined path
+ */
+QString ReFileUtils::pathAppend(const QString& base, const QString& path) {
+       QString rc;
+       if (isAbsolutPath(path))
+               rc = path;
+       else if (!base.isEmpty())
+               rc = QDir::cleanPath(base + OS_SEPARATOR + path);
+       else {
+               rc = path;
+               rc.replace("\\", "/");
+               if (path.startsWith("/"))
+                       rc.remove(0, 1);
+       }
+       return rc;
+}
+
+/**
+ * Appends a relative path to base directory name (absolute or relative).
+ *
+ * @param base the base directory, relative or absolute
+ * @param path a relative path (relative to <code>base</code>)
+ * @return      <code>path</code> if it is an absolute path<br>
+ *                             otherwise: the combined path
+ */
+QByteArray ReFileUtils::pathAppend(const char* base, const char* path) {
+       QByteArray rc;
+       if (base[0] != '\0') {
+               rc.append(base).append(OS_SEPARATOR).append(path);
+       } else {
+               rc = path;
+       }
+       return rc = cleanPath(rc);
+}
+
 /**
  * Delete a directory tree.
  *
@@ -84,6 +125,67 @@ bool ReFileUtils::deleteTree(const QString& path, bool withBase,
        }
        return rc;
 }
+
+/**
+ * Extracts the extension of a filename.
+ *
+ * The extension is the last part of a node separated by a '.'.
+ * The separator '.' in part of the extension.
+ * If the node starts with the only dot the extension is empty.
+ *
+ * Works with '/' and with '\\'.
+ *
+ * @param filename  the filename (with or without path)
+ * @return          "": no extension found<br>
+ *                  otherwise: the extension of <code>filename</code>
+ */
+QString ReFileUtils::extensionOf(const QString& filename) {
+       QString rc;
+       int ix = max(0, filename.size() - 1);
+       QChar cc;
+       while (ix > 0) {
+               if ((cc = filename.at(ix)) == QChar('.')) {
+                       if ((cc = filename.at(ix - 1)) != '/' && cc != '\\')
+                               rc = filename.mid(ix);
+                       break;
+               } else if (cc == QChar('\\') || cc == QChar('/'))
+                       break;
+               ix--;
+       }
+       return rc;
+}
+
+/**
+ * Extracts the extension of a filename.
+ *
+ * The extension is the last part of a node separated by a '.'.
+ * The separator '.' in part of the extension.
+ * If the node starts with the only dot the extension is empty.
+ *
+ * Works with '/' and with '\\'.
+ *
+ * @param filename  the filename (with or without path)
+ * @return          "": no extension found<br>
+ *                  otherwise: the extension of <code>filename</code>
+ */
+QByteArray ReFileUtils::extensionOf(const char* filename) {
+       QByteArray rc;
+       if (filename[0] != '\0') {
+               size_t ix = strlen(filename) - 1;
+               char cc;
+               while (ix > 0) {
+                       if ((cc = filename[ix]) == '.') {
+                               if ((cc = filename[ix - 1]) != '/' && cc != '\\')
+                                       rc.append(filename + ix);
+                               break;
+                       } else if (cc == '\\' or cc == '/')
+                               break;
+                       ix--;
+               }
+       }
+       return rc;
+}
+
 /**
  * Returns whether a path is an absolute path.
  *
@@ -120,6 +222,121 @@ bool ReFileUtils::isAbsolutPath(const char* path) {
        return rc;
 }
 
+/**
+ * Extracts the node of a filename.
+ *
+ * The node is the filename without path.
+ *
+ * @param filename  the filename (with or without path)
+ * @return          the node of <code>filename</code>
+ */
+QString ReFileUtils::nodeOf(const QString& filename) {
+       QString 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;
+       return rc;
+}
+
+/**
+ * Extracts the node of a filename.
+ *
+ * The node is the filename without path.
+ *
+ * @param filename  the filename (with or without path)
+ * @return          the node of <code>filename</code>
+ */
+QByteArray ReFileUtils::nodeOf(const char* filename) {
+       QByteArray rc;
+       int ix = (int) strlen(filename) - 1;
+       while (ix >= 0) {
+               if (filename[ix] == '/' || filename[ix] == '\\') {
+                       rc.append(filename + ix + 1);
+                       break;
+               }
+               ix--;
+       }
+       if (ix < 0)
+               rc = filename;
+       return rc;
+}
+
+/** Normalizes a file path.
+ *
+ * Removes duplicated slashes and "." and "..", but not leading ".."
+ *
+ * @param path path to clean
+ * @return             the path without duplicated separators and "." and ".."
+ */
+QByteArray ReFileUtils::cleanPath(const char* path) {
+       QByteArray rc;
+       int length = strlen(path);
+       rc.reserve(length);
+       int minLength = 0;
+#ifdef __WIN32__
+       // UNC path, e.g. "\\server\share"?
+       if (path[0] == OS_SEPARATOR && path[1] == OS_SEPARATOR) {
+               rc.append("\\\\");
+               path += 2;
+               minLength = 2;
+       }
+#endif
+       const char* ptr;
+       if (path[0] == OS_SEPARATOR) {
+               rc.append(OS_SEPARATOR);
+               path++;
+       }
+       while ((ptr = strchr(path, OS_SEPARATOR)) != NULL) {
+               // ignore duplicated slashes:
+               if (ptr != path) {
+                       int length = ptr - path;
+                       if (length == 1 && path[0] == '.') {
+                               // ignore ".": do nothing
+                       } else if (length == 2 && path[0] == '.' && path[1] == '.') {
+                               // remove the last slash and node
+                               if (rc.size() > minLength) {
+                                       rc.resize(rc.size() - 1);
+                                       int ix = rc.lastIndexOf(OS_SEPARATOR);
+                                       if (ix > minLength)
+                                               rc.resize(ix + 1);
+                               }
+
+                       } else {
+                               // copy with separator:
+                               rc.append(path, length + 1);
+                       }
+
+               }
+               path = ptr + 1;
+       }
+       if (path[0] != '\0') {
+               if (path[0] == '.' && path[1] == '\0') {
+                       if (rc.size() == 0)
+                               rc.append('.');
+               } else if (path[0] == '.' && path[1] == '.' && path[3] == '\0') {
+                       // remove the last slash and node
+                       if (rc.size() > minLength) {
+                               rc.resize(rc.size() - 1);
+                               int ix = rc.lastIndexOf(OS_SEPARATOR);
+                               if (ix > minLength)
+                                       rc.resize(ix);
+                       }
+               } else {
+                       // copy with separator:
+                       rc.append(path);
+               }
+       }
+       return rc;
+}
+
 /**
  * Reads a string from a given file.
  *
@@ -142,6 +359,45 @@ QByteArray& ReFileUtils::readFromFile(const char* filename,
        return buffer;
 }
 
+/**
+ * Replaces the file extension of a filename.
+ *
+ * @param path  the filename to change
+ * @param ext   the new file extension, e.g. ".txt"
+ * @return      path with a new file extension
+ */
+
+QString ReFileUtils::replaceExtension(const QString& path, const QString& ext) {
+       QString oldExt = extensionOf(path);
+       QString rc;
+       if (oldExt.isEmpty())
+               rc = path + ext;
+       else
+               rc = path.mid(0, path.size() - oldExt.size()) + ext;
+       return rc;
+}
+/**
+ * Replaces the file extension of a filename.
+ *
+ * @param path  the filename to change
+ * @param ext   the new file extension, e.g. ".txt"
+ * @return      path with a new file extension
+ */
+
+QByteArray ReFileUtils::replaceExtension(const char* path, const char* ext) {
+       QByteArray oldExt = extensionOf(path);
+       QByteArray rc;
+       if (oldExt.isEmpty())
+               rc.append(path).append(ext);
+       else {
+               size_t length = strlen(path);
+               size_t lengthExt = strlen(ext);
+               rc.reserve(length - oldExt.size() + lengthExt);
+               rc.append(path, length - oldExt.size());
+               rc.append(ext);
+       }
+       return rc;
+}
 /**
  * Sets the filetimes.
  *
@@ -259,6 +515,22 @@ QByteArray ReFileUtils::tempDir(const char* node, const char* parent,
                temp.resize(temp.length() - 1);
        return temp;
 }
+/**
+ * @brief Returns the name of a directory in the temp dir.
+ *
+ * If the named directory does not exist it will be created.
+ *
+ * @param node          NULL or the node (name without path)
+ * @param parent        NULL or a node of the parent
+ * @param withSeparator true: the result ends with slash/backslash
+ * @return              the name of an existing directory
+ */
+QByteArray ReFileUtils::tempDirEmpty(const char* node, const char* parent,
+    bool withSeparator) {
+       QByteArray rc = tempDir(node, parent, withSeparator);
+       deleteTree(rc, false, NULL);
+       return rc;
+}
 
 /**
  * @brief Returns a name of a file in a temporary directory.
index ebbc48b2ddd7dc8c51da9af51ecb8b2338501ff4..3b276363b0b01d4cc10164768840394a376d60fd 100644 (file)
@@ -30,15 +30,26 @@ class ReFileUtils {
 public:
        static bool deleteTree(const QString& path, bool withBase,
            ReLogger* logger);
+       static QByteArray cleanPath(const char* path);
+       static QString extensionOf(const QString& filename);
+       static QByteArray extensionOf(const char* filename);
        static bool isAbsolutPath(const QString& path);
        static bool isAbsolutPath(const char* path);
+       static QString nodeOf(const QString& filename);
+       static QByteArray nodeOf(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);
+       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 setTimes(const char* filename, const QDateTime& modified,
            const QDateTime& accessed = m_undefinedTime, ReLogger* logger = NULL);
        static int64_t tell(FILE* file);
        static QByteArray tempDir(const char* node, const char* parent = NULL,
            bool withSeparator = true);
+       static QByteArray tempDirEmpty(const char* node, const char* parent = NULL,
+           bool withSeparator = true);
        static QByteArray tempFile(const char* node, const char* parent = NULL,
            bool deleteIfExists = true);
        static void writeToFile(const char* filename, const char* content,
index d605a46af123047e9f58ad2847ae7e35c8b50c96..9d816f5da6112d08efd56685255f625b99e8676a 100644 (file)
@@ -66,35 +66,6 @@ QString& ReQStringUtils::ensureLastChar(QString& value, QChar lastChar) {
        return value;
 }
 
-/**
- * Extracts the extension of a filename.
- *
- * @param filename  the filename (with or without path)
- * @return          "": no extension found<br>
- *                  otherwise: the extension of <code>filename</code>
- */
-ReString ReQStringUtils::extensionOf(const ReString& filename) {
-       QString rc;
-       int index = filename.lastIndexOf('.');
-       int index2 = 0;
-       if (index > 0) {
-               index2 = filename.lastIndexOf('/');
-               if (index2 >= 0) {
-                       if (index > index2)
-                               rc = filename.mid(index);
-               } else {
-#if defined __linux__
-                       rc = filename.mid(index);
-#elif defined WIN32
-                       index2 = filename.lastIndexOf('\\');
-                       if (index2 < 0 || index > index2)
-                       rc = filename.mid(index);
-#endif
-               }
-       }
-       return rc;
-}
-
 /**
  * @brief Determines the length and vlaue of an integer.
  *
@@ -396,70 +367,6 @@ int ReQStringUtils::lengthOfReal(const ReString& text, int start,
        return found ? ix - start : 0;
 }
 
-/**
- * Extracts the node of a filename.
- *
- * The node is the filename without path.
- *
- * @param filename  the filename (with or without path)
- * @return          the node of <code>filename</code>
- */
-ReString ReQStringUtils::nodeOf(const ReString& filename) {
-       QString rc;
-
-       int index = filename.lastIndexOf('/');
-       if (index >= 0)
-               rc = filename.mid(index + 1);
-       else {
-#if defined WIN32
-               index = filename.lastIndexOf('\\');
-               if (index < 0)
-               rc = filename;
-               else
-               rc = filename.mid(index + 1);
-#endif
-       }
-       return rc;
-}
-
-/**
- * Appends a relative path to base directory name (absolute or relative).
- *
- * @param base  the base directory, relative or absolute
- * @param toAdd a relative path (relative to <code>base</code>)
- * @return      the combined path
- */
-QString ReQStringUtils::pathAppend(const QString& base, const QString& path) {
-       QString rc;
-       if (!base.isEmpty())
-               rc = QDir::cleanPath(base + QDir::separator() + path);
-       else {
-               rc = path;
-               rc.replace("\\", "/");
-               if (path.startsWith("/"))
-                       rc.remove(0, 1);
-       }
-       return rc;
-}
-
-/**
- * Replaces the file extension of a filename.
- *
- * @param path  the filename to change
- * @param ext   the new file extension, e.g. ".txt"
- * @return      path with a new file extension
- */
-
-QString ReQStringUtils::replaceExtension(const QString& path,
-    const QString& ext) {
-       QString oldExt = extensionOf(path);
-       QString rc;
-       if (oldExt.isEmpty())
-               rc = path + ext;
-       else
-               rc = path.mid(0, path.size() - oldExt.size()) + ext;
-       return rc;
-}
 /**
  * Replaces placeholders by their values.
  *
index e0e4934a183d498abe1d7a0854663a38e69f559f..b883cb370db983c64127f7955cbde0fb9ed53941 100644 (file)
@@ -20,7 +20,8 @@ public:
        static ReString chomp(const ReString& text);
        static int countOf(const QString& value, QChar toFind, int start = 0);
        static QString& ensureLastChar(QString& value, QChar lastChar);
-       static ReString extensionOf(const ReString& filename);
+       static QString extensionOf(const QString& filename);
+       static QByteArray extensionOf(const char* filename);
        static int lengthOfDate(const ReString& text, int start = 0, QDate* value =
            NULL);
        static int lengthOfDateTime(const ReString& text, int start = 0,
@@ -48,9 +49,6 @@ public:
                return path;
 #endif
        }
-       static ReString nodeOf(const ReString& filename);
-       static QString pathAppend(const QString& base, const QString& path);
-       static QString replaceExtension(const QString& path, const QString& ext);
        static bool replacePlaceholders(QString& text,
            const QMap<QString, QString>& placeholders, QString* error);
        static void skipExpected(const ReString& text, QChar expected, int& index,
index 2ed6ad69a6eabceb0bcd993b7071e745c4f1ab61..39abdcbd553f7552fd17b7a5dba406ca04bdf45c 100644 (file)
 class TestReFileSystem: public ReTest {
 public:
        TestReFileSystem() :
-                       ReTest("ReFileSystem") {
+                   ReTest("ReFileSystem") {
                doIt();
        }
 private:
        QByteArray m_base;
        QByteArray m_subDir1;
 protected:
-       void init(){
+       void init() {
                m_base = ReFileUtils::tempDir("refilesystem");
                m_subDir1 = ReFileUtils::tempDir("dir1", "refilesystem");
                ReFileUtils::tempDir("dir2", "refilesystem");
                QString node;
-               for (int ix = 1; ix <= 7; ix++){
+               for (int ix = 1; ix <= 7; ix++) {
                        node.sprintf("test%d.txt", ix);
                        QByteArray fn = ReFileUtils::tempFile(node.toUtf8().constData(),
-                               "refilesystem", false);
+                           "refilesystem", false);
                        ReFileUtils::writeToFile(fn.constData(), node.toUtf8().constData());
                        fn = m_subDir1;
                        fn.append("text").append(QByteArray::number(ix));
@@ -41,14 +41,14 @@ protected:
                }
                ReFileUtils::tempFile("abc.txt", "refilesytem", true);
        }
-       void testContains(const char* name, ReFileMetaDataList nodes){
+       void testContains(const char* name, ReFileMetaDataList nodes) {
                bool rc = false;
                ReFileMetaDataList::const_iterator it;
-               for (it = nodes.cbegin(); it != nodes.cend(); ++it){
+               for (it = nodes.cbegin(); it != nodes.cend(); ++it) {
                        if ((*it).m_node == name)
                                rc = true;
                }
-               if (! rc)
+               if (!rc)
                        checkT(rc);
        }
 
@@ -58,13 +58,13 @@ protected:
                checkEqu(QString(m_base), fs.basePath());
                ReFileMetaDataList nodes;
                ReIncludeExcludeMatcher matcher(ReListMatcher::allMatchingList(),
-                       ReQStringUtils::m_emptyList, Qt::CaseInsensitive, false);
+                   ReQStringUtils::m_emptyList, Qt::CaseInsensitive, false);
                fs.listInfos(matcher, nodes);
                testContains("dir1", nodes);
                testContains("test1.txt", nodes);
                testContains("test7.txt", nodes);
        }
-       void testReadWrite(){
+       void testReadWrite() {
                ReLocalFileSytem fs(m_base, &m_logger);
                QByteArray buffer;
                buffer.append("abcdefghijklmnopqrstuvwxyz");
@@ -74,8 +74,8 @@ protected:
                ReFileMetaDataList nodes;
                QStringList names;
                names.append("abc.txt");
-               ReIncludeExcludeMatcher matcher(names,
-                       ReQStringUtils::m_emptyList, Qt::CaseInsensitive, true);
+               ReIncludeExcludeMatcher matcher(names, ReQStringUtils::m_emptyList,
+                   Qt::CaseInsensitive, true);
                checkEqu(1, fs.listInfos(matcher, nodes));
                checkEqu(1, nodes.size());
                checkEqu(0, fs.read(nodes.at(0), 0LL, 3, buffer2));
@@ -85,13 +85,81 @@ protected:
                checkEqu(0, fs.read(nodes.at(0), 10LL, 99, buffer2));
                checkEqu("klmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", buffer2);
        }
-       void testCopy(){
+       void testSetProperties() {
+               ReLocalFileSytem fs(m_base, &m_logger);
+               ReFileMetaData meta1;
+               const char* trgNode = "later.txt";
+               ReFileUtils::tempFile(trgNode, "refilesystem", true);
+               QDateTime modified = QDateTime::fromString("2015.09.12 11:44:55.765",
+                   "yyyy.MM.dd hh:mm:ss.zzz");
+               ReFileMetaData meta2(trgNode, modified, ReFileUtils::m_undefinedTime,
+                   -1, -1, (mode_t) - 1, 1);
+               checkT(fs.first("test1.txt", meta1));
+               checkEqu(0, fs.setProperties(meta2, meta1, true));
+               ReFileMetaData meta3;
+               checkT(fs.first(trgNode, meta3));
+               checkEqu(meta3.m_modified, modified);
+       }
+       void testSetPropertiesOwner() {
+#ifdef __linux__
+               if (geteuid() == 0) {
+                       ReLocalFileSytem fs(m_base, &m_logger);
+                       ReFileMetaData meta1;
+                       ReFileUtils::tempFile("later2.txt", "refilesystem", true);
+                       int rights = S_IRUSR | S_IWGRP | S_IRGRP| S_IROTH | S_IWOTH;
+                       QDateTime modified = QDateTime::fromString("2015.08.13 10:34:55.765",
+                               "yyyy.MM.dd hh:mm:ss:zzz");
+                       ReFileMetaData meta2("later2.txt",
+                               modified, ReFileUtils::m_undefinedTime,
+                               1001, 1002, rights, 1);
+                       checkT(fs.first("test2.txt", meta1));
+                       checkEqu(0, fs.setProperties(meta2, meta1, true));
+                       ReFileMetaData meta3;
+                       checkT(fs.first("later2.txt", meta3));
+                       checkEqu(meta3.m_modified, modified);
+                       checkEqu(meta3.m_owner, 1001);
+                       checkEqu(meta3.m_group, 1002);
+                       checkEqu(meta3.m_mode & ALLPERMS, rights);
+               }
+#endif
+
+       }
+       void compareMeta(ReFileMetaData& meta1, ReFileMetaData& meta2) {
+               checkEqu(meta1.m_node, meta2.m_node);
+               checkEqu(meta1.m_modified, meta2.m_modified);
+               checkEqu((int ) meta1.m_mode, (int ) meta2.m_mode);
+               checkEqu(meta1.m_group, meta2.m_group);
+               checkEqu(meta1.m_owner, meta2.m_owner);
+               checkEqu(meta1.m_size, meta2.m_size);
+       }
 
+       void testCopy() {
+               ReLocalFileSytem fsSource(m_base, &m_logger);
+               QByteArray base2 = ReFileUtils::tempDir("refilesystem.trg", NULL,
+                   false);
+               ReFileUtils::deleteTree(base2, false, &m_logger);
+               ReLocalFileSytem fsTarget(base2, &m_logger);
+               ReFileMetaData metaSource;
+               checkT(fsSource.first("test3.txt", metaSource));
+               checkEqu(0, fsTarget.copy(metaSource, fsSource));
+               ReFileMetaData metaTarget;
+               checkT(fsTarget.first("test3.txt", metaTarget));
+               compareMeta(metaSource, metaTarget);
+               checkEqu(0, fsTarget.makeDir("dir.01"));
+               checkEqu(0, fsTarget.setDirectory("dir.01"));
+               checkEqu(0, fsTarget.copy(metaSource, fsSource));
+               QString path = fsTarget.fullName(metaSource.m_node);
+               checkT(path.indexOf("dir.01"));
+               struct stat info;
+               checkEqu(0, stat(path.toUtf8().constData(), &info));
        }
 
        virtual void run() {
                init();
                testReListInfos();
+               testSetProperties();
+               testSetPropertiesOwner();
+               testCopy();
                testReadWrite();
        }
 };
index 2b033c190424ef8798cd70bcd73edc4f04cc0d6c..c3d21e4bdf7f3dcd345dd8665393ebe8e0c790f4 100644 (file)
@@ -17,7 +17,7 @@
 class TestReFileUtils: public ReTest {
 public:
        TestReFileUtils() :
-                       ReTest("ReFileUtils") {
+                   ReTest("ReFileUtils") {
                doIt();
        }
 
@@ -40,6 +40,17 @@ public:
                checkEqu(0, stat(dir, &info));
                checkT(S_ISDIR(info.st_mode));
        }
+       void testTempDirEmpty() {
+               QByteArray dir(
+                   ReFileUtils::tempDirEmpty("subdir2", "cuReFileUtils", true));
+               QByteArray subdir(dir);
+               subdir.append("subdirX");
+               mkdir(subdir.constData(), ALLPERMS);
+               struct stat info;
+               checkEqu(0, stat(subdir.constData(), &info));
+               ReFileUtils::tempDirEmpty("subdir2", "cuReFileUtils", true);
+               checkEqu(-1, stat(subdir.constData(), &info));
+       }
        void testWriteRead() {
                QByteArray fn(ReFileUtils::tempFile("node.txt", "subdir", true));
                ReFileUtils::writeToFile(fn, "123");
@@ -50,13 +61,13 @@ public:
                ReFileUtils::readFromFile(fn, content);
                checkEqu("ab", content);
        }
-       QByteArray buildTree(){
+       QByteArray buildTree() {
                QByteArray base = ReFileUtils::tempDir("ReFileUtils");
-               for (char cc = 'a'; cc < 'f'; cc++){
+               for (char cc = 'a'; cc < 'f'; cc++) {
                        QByteArray subdir(base + cc);
                        mkdir(subdir.constData(), ALLPERMS);
-                       for (char cc2 = '1'; cc2 < '5'; cc2++){
-                               QByteArray name( subdir);
+                       for (char cc2 = '1'; cc2 < '5'; cc2++) {
+                               QByteArray name(subdir);
                                name.append(OS_SEPARATOR_STR).append(&cc2, 1);
                                ReFileUtils::writeToFile(name, name);
                                name += "dir";
@@ -69,7 +80,7 @@ public:
                base.remove(base.length() - 1, 1);
                return base;
        }
-       void testDeleteTree(){
+       void testDeleteTree() {
                QByteArray base = buildTree();
                checkT(ReFileUtils::deleteTree(QString(base), false, &m_logger));
                struct stat info;
@@ -81,7 +92,7 @@ public:
                checkT(ReFileUtils::deleteTree(QString(base), false, &m_logger));
                checkEqu(0, stat(base, &info));
        }
-       void testIsAbsolutePath(){
+       void testIsAbsolutePath() {
 #ifdef __linux__
                checkT(ReFileUtils::isAbsolutPath("/abc/def/xyz.123"));
                checkT(ReFileUtils::isAbsolutPath("/"));
@@ -97,12 +108,12 @@ public:
 #endif
                checkF(ReFileUtils::isAbsolutPath(""));
        }
-       void testSeekTell(){
+       void testSeekTell() {
                QByteArray fn(ReFileUtils::tempFile("seektest.txt", NULL, false));
                ReFileUtils::writeToFile(fn.constData(), "0123456789");
                FILE* fp = fopen(fn.constData(), "rb");
                checkNN(fp);
-               if (fp != NULL){
+               if (fp != NULL) {
                        checkEqu(0LL, ReFileUtils::tell(fp));
                        checkEqu(0, ReFileUtils::seek(fp, 3, SEEK_SET));
                        checkEqu(3LL, ReFileUtils::tell(fp));
@@ -117,10 +128,171 @@ public:
                        checkEqu(0, ReFileUtils::seek(fp, -2, SEEK_END));
                        checkEqu(8LL, ReFileUtils::tell(fp));
                }
+       }
+       void testSetTimes() {
+               QByteArray fn(ReFileUtils::tempFile("timetest.txt", NULL, true));
+               ReFileUtils::writeToFile(fn.constData(), "");
+               QDateTime time = QDateTime::fromString("03.09.2015 07:14:24.432",
+                   "dd.MM.yyyy hh:mm:ss.zzz");
+               checkT(
+                   ReFileUtils::setTimes(fn.constData(), time,
+                       ReFileUtils::m_undefinedTime, &m_logger));
+               QFileInfo info(fn);
+               checkEqu(time, info.lastModified());
+       }
+       void testCleanPath() {
+#if defined __linux__
+               // no change:
+               checkEqu("/x/y/z.x", ReFileUtils::cleanPath("/x/y/z.x"));
+               checkEqu("x/y/z.x", ReFileUtils::cleanPath("./x/y/z.x"));
+               checkEqu("x/y/z.x/", ReFileUtils::cleanPath("x/y/z.x/"));
+               // remove duplicated slashes:
+               checkEqu("x/y/z.x/", ReFileUtils::cleanPath("x//y/////z.x//"));
+               // remove "./"
+               checkEqu("x/y/z.x", ReFileUtils::cleanPath("./x/././y/z.x"));
+               // remove "..":
+               // inside...
+               checkEqu("x/y/a/b", ReFileUtils::cleanPath("x/y/z/../a/b"));
+               checkEqu("x/a/b", ReFileUtils::cleanPath("x/y/z/../../a/b"));
+               // at the end..
+               checkEqu("x", ReFileUtils::cleanPath("x/y/z/../.."));
+               // wrong forms:
+               checkEqu("..", ReFileUtils::cleanPath(".."));
+               checkEqu("../..", ReFileUtils::cleanPath("../.."));
+               checkEqu("..", ReFileUtils::cleanPath("../x/.."));
+
+#elif defined __WIN32__
+#error "not implemented"
+#endif
+       }
+       void checkExtensionOf(const char* expected, const char* arg1, int lineNo) {
+               assertEquals(QString(expected), ReFileUtils::extensionOf(QString(arg1)),
+               __FILE__, lineNo);
+               assertEquals(expected, ReFileUtils::extensionOf(QString(arg1)),
+               __FILE__, lineNo);
+               QByteArray exp(expected);
+               QByteArray sArg1(arg1);
+               exp.replace("/", "\\");
+               sArg1.replace("/", "\\");
+               assertEquals(QString(exp), ReFileUtils::extensionOf(QString(sArg1)),
+               __FILE__, lineNo);
+               assertEquals(exp.constData(),
+                   ReFileUtils::extensionOf(sArg1.constData()),
+                   __FILE__, lineNo);
+       }
+
+       void testExtensionOf() {
+               checkExtensionOf("", "", __LINE__);
+               // full path
+               checkExtensionOf(".x", "/abc/def.x", __LINE__);
+               // prior node with extension too:
+               checkExtensionOf(".xyz", "/abc.z/def.xyz", __LINE__);
+               // sizeof (ext) == 2:
+               checkExtensionOf(".x", "/abc.z/def.xx.x", __LINE__);
+               // sizeof (ext) == 1:
+               checkExtensionOf(".x", "def.x", __LINE__);
+               checkExtensionOf(".", "def.", __LINE__);
+               // empty extension:
+               checkExtensionOf("", "/abc.x/def", __LINE__);
+               // empty last node:
+               checkExtensionOf("", "/abc.x/", __LINE__);
+               // node starting with "."
+               checkExtensionOf("", "/abc.x/.x", __LINE__);
+               checkExtensionOf("", ".xyz", __LINE__);
+               // Special:
+               checkExtensionOf("", "", __LINE__);
+       }
+       void checkNodeOf(const char* expected, const char* toTest, int lineNo) {
+               assertEquals(QString(expected), ReFileUtils::nodeOf(QString(toTest)),
+               __FILE__, lineNo);
+               assertEquals(expected, ReFileUtils::nodeOf(QString(toTest)),
+               __FILE__, lineNo);
+               QByteArray exp(expected);
+               QByteArray toTst(toTest);
+               exp.replace("/", "\\");
+               toTst.replace("/", "\\");
+               assertEquals(QString(exp), ReFileUtils::nodeOf(QString(toTst)),
+               __FILE__, lineNo);
+               assertEquals(exp, ReFileUtils::nodeOf(toTst.constData()),
+               __FILE__, lineNo);
+       }
+
+       void testNodeOf() {
+               checkNodeOf("abc.def", "/abc.def", __LINE__);
+               checkNodeOf("abc.def", "abc.def", __LINE__);
+               checkNodeOf("abc.def", "x/y/abc.def", __LINE__);
+               checkNodeOf("abc", "x/y/abc", __LINE__);
+               checkNodeOf("", "", __LINE__);
+       }
+
+       void checkPathAppend(const char* expected, const char* arg1,
+           const char* arg2, int lineNo) {
+               assertEquals(QString(expected),
+                   ReFileUtils::pathAppend(QString(arg1), QString(arg2)),
+                   __FILE__, lineNo);
+               assertEquals(expected, ReFileUtils::pathAppend(arg1, arg2),
+               __FILE__, lineNo);
+               QByteArray exp(expected);
+               QByteArray sArg1(arg1);
+               QByteArray sArg2(arg2);
+               exp.replace("/", "\\");
+               sArg1.replace("/", "\\");
+               sArg2.replace("/", "\\");
+               assertEquals(QString(exp),
+                   ReFileUtils::pathAppend(QString(sArg1), QString(sArg2)),
+                   __FILE__, lineNo);
+               assertEquals(exp,
+                   ReFileUtils::pathAppend(sArg1.constData(), sArg2.constData()),
+                   __FILE__, lineNo);
 
        }
+       void testPathAppend() {
+               // no base:
+               checkPathAppend("abc/def", "", "abc/def", __LINE__);
+               checkPathAppend("abc/def", NULL, "abc/def", __LINE__);
+               // abs path:
+               checkPathAppend("/abc/def", "", "/abc/def", __LINE__);
+               checkPathAppend("/abc/def", NULL, "/abc/def", __LINE__);
+               checkPathAppend("/abc/def", "xyz", "/abc/def", __LINE__);
+               // true combination:
+               checkPathAppend("/abc/bef", "/abc", "bef", __LINE__);
+               checkPathAppend("/abc/bef", "/abc/", "bef", __LINE__);
+               checkPathAppend("/abc", "/", "bef", __LINE__);
+       }
+       void checkReplaceExt(const char* expected, const char* arg1,
+           const char* arg2, int lineNo) {
+               assertEquals(QString(expected),
+                   ReFileUtils::replaceExtension(QString(arg1), QString(arg2)),
+                   __FILE__, lineNo);
+               assertEquals(expected, ReFileUtils::replaceExtension(arg1, arg2),
+               __FILE__, lineNo);
+               QByteArray exp(expected);
+               QByteArray sArg1(arg1);
+               QByteArray sArg2(arg2);
+               exp.replace("/", "\\");
+               sArg1.replace("/", "\\");
+               sArg2.replace("/", "\\");
+               assertEquals(QString(exp),
+                   ReFileUtils::replaceExtension(QString(sArg1), QString(sArg2)),
+                   __FILE__, lineNo);
+               assertEquals(exp,
+                   ReFileUtils::replaceExtension(sArg1.constData(), sArg2.constData()),
+                   __FILE__, lineNo);
+
+       }
+       void testReplaceExtension() {
+               checkReplaceExt("/abc/def.123", "/abc/def.xyz", ".123", __LINE__);
+               checkReplaceExt("def.123", "def.xyz", ".123", __LINE__);
+               checkReplaceExt("/abc.1/def.123", "/abc.1/def.xyz", ".123", __LINE__);
+               checkReplaceExt("/abc.1/def.123", "/abc.1/def", ".123", __LINE__);
+       }
 
        virtual void run() {
+               testReplaceExtension();
+               testNodeOf();
+               testExtensionOf();
+               testCleanPath();
+               testSetTimes();
                testSeekTell();
                testIsAbsolutePath();
                testDeleteTree();
index 0711f787a2d4ab0d511d9b09aa7497f1e2a6218a..cdfa81f0623c8384f6cb038b9350654cd8c3f3a7 100644 (file)
@@ -17,7 +17,7 @@
 class TestReQStringUtil: public ReTest {
 public:
        TestReQStringUtil() :
-                       ReTest("ReQStringUtil") {
+                   ReTest("ReQStringUtil") {
                doIt();
        }
 
@@ -35,20 +35,20 @@ public:
        void testLengthOfUInt64() {
                quint64 value = -3;
                checkEqu(1,
-                       ReQStringUtils::lengthOfUInt64(ReString("0"), 0, 10, &value));
+                   ReQStringUtils::lengthOfUInt64(ReString("0"), 0, 10, &value));
                checkEqu(int64_t(0), value);
                checkEqu(3, ReQStringUtils::lengthOfUInt64("x432", 1, 10, &value));
                checkEqu(int64_t(432LL), value);
                checkEqu(3, ReQStringUtils::lengthOfUInt64("x432 x", 1, 10, &value));
                checkEqu(int64_t(432LL), value);
                checkEqu(3,
-                       ReQStringUtils::lengthOfUInt64("x432fabc x", 1, 10, &value));
+                   ReQStringUtils::lengthOfUInt64("x432fabc x", 1, 10, &value));
                checkEqu(int64_t(432LL), value);
                checkEqu(16,
-                       ReQStringUtils::lengthOfUInt64("a1234567890123567", 1, 10, &value));
+                   ReQStringUtils::lengthOfUInt64("a1234567890123567", 1, 10, &value));
                checkEqu(int64_t(1234567890123567LL), value);
                checkEqu(10,
-                       ReQStringUtils::lengthOfUInt64("x1234abcdef", 1, 16, &value));
+                   ReQStringUtils::lengthOfUInt64("x1234abcdef", 1, 16, &value));
                checkEqu(int64_t(0x1234abcdefLL), value);
                checkEqu(3, ReQStringUtils::lengthOfUInt64("432", 0, 8, &value));
                checkEqu(int64_t(0432LL), value);
@@ -85,19 +85,19 @@ public:
                checkEqu(1, ReQStringUtils::lengthOfReal(ReString(" 0"), 1, &value));
                checkEqu(0.0, value);
                checkEqu(17,
-                       ReQStringUtils::lengthOfReal(ReString("X12345678901234567"), 1,
-                               &value));
+                   ReQStringUtils::lengthOfReal(ReString("X12345678901234567"), 1,
+                       &value));
                checkEqu(12345678901234567.0, value);
                checkEqu(2, ReQStringUtils::lengthOfReal(ReString(".5"), 0, &value));
                checkEqu(0.5, value);
                checkEqu(5,
-                       ReQStringUtils::lengthOfReal(ReString("2.5e2x"), 0, &value));
+                   ReQStringUtils::lengthOfReal(ReString("2.5e2x"), 0, &value));
                checkEqu(250.0, value);
                checkEqu(6,
-                       ReQStringUtils::lengthOfReal(ReString("2.5e+2"), 0, &value));
+                   ReQStringUtils::lengthOfReal(ReString("2.5e+2"), 0, &value));
                checkEqu(250.0, value);
                checkEqu(7,
-                       ReQStringUtils::lengthOfReal(ReString("2.5E-33"), 0, &value));
+                   ReQStringUtils::lengthOfReal(ReString("2.5E-33"), 0, &value));
                checkEqu(2.5e-33, value);
 
                checkEqu(3, ReQStringUtils::lengthOfReal(ReString("2.5E"), 0, &value));
@@ -105,7 +105,7 @@ public:
                checkEqu(3, ReQStringUtils::lengthOfReal(ReString("2.5E+"), 0, &value));
                checkEqu(2.5, value);
                checkEqu(3,
-                       ReQStringUtils::lengthOfReal(ReString("2.5E-a"), 0, &value));
+                   ReQStringUtils::lengthOfReal(ReString("2.5E-a"), 0, &value));
                checkEqu(2.5, value);
        }
 
@@ -128,7 +128,7 @@ public:
                ReString name = "Heinz Müller";
                char buffer[32];
                checkEqu("Heinz Müller",
-                       ReQStringUtils::utf8(name, buffer, sizeof buffer));
+                   ReQStringUtils::utf8(name, buffer, sizeof buffer));
                memset(buffer, 'x', sizeof buffer);
                checkEqu("Heinz", ReQStringUtils::utf8(name, buffer, (size_t)(5 + 1)));
                checkEqu(buffer[6], 'x');
index 9f23df3fc16863f1cc746c5ea89facc09c3b6166..06c819df284cac81d4ffd9b7f5dba21752db2cda 100644 (file)
@@ -38,12 +38,16 @@ enum {
  * @param name the name of the filesystem
  */
 ReFileSystem::ReFileSystem(const QString& name, ReLogger* logger) :
-           m_name(name),
-           m_writeable(false),
-           m_logger(logger),
-           m_buffer(),
-           m_blocksize(4 * 1024 * 1024),
-           m_undefinedTime() {
+               m_name(name),
+#ifdef __linux__
+               m_uid(geteuid()),
+               m_gid(getegid()),
+#endif
+               m_writeable(false),
+               m_logger(logger),
+               m_buffer(),
+               m_blocksize(4 * 1024 * 1024),
+               m_undefinedTime() {
 
 }
 
@@ -62,14 +66,14 @@ ReFileSystem::~ReFileSystem() {
  *
  */
 ReFileSystem::ErrorCode ReFileSystem::copy(ReFileMetaData& source,
-    ReFileSystem& sourceFS) {
+       ReFileSystem& sourceFS) {
        int blocksize = min(m_blocksize, sourceFS.blocksize());
        ErrorCode rc = EC_SUCCESS;
        ErrorCode rc2;
        int64_t size = 0;
        while (rc == EC_SUCCESS && size < source.m_size) {
                if ((rc2 = sourceFS.read(source, size, blocksize, m_buffer))
-                   != EC_SUCCESS)
+                       != EC_SUCCESS)
                        rc = rc2;
                else if ((rc2 = write(source.m_node, size, m_buffer)) != EC_SUCCESS)
                        rc = rc2;
@@ -77,9 +81,21 @@ ReFileSystem::ErrorCode ReFileSystem::copy(ReFileMetaData& source,
        }
        close();
        sourceFS.close();
+       ReFileMetaData target(source.m_node, ReFileUtils::m_undefinedTime,
+                       ReFileUtils::m_undefinedTime, m_uid, m_gid);
+       setProperties(source, target, false);
        return rc;
 }
 
+/**
+ * Returns the name of the current directory.
+ *
+ * @return     the name of the current directory
+ */
+const QString& ReFileSystem::directory() const {
+       return m_directory;
+}
+
 /**
  * Returns whether the filesystem is writeable.
  *
@@ -120,7 +136,7 @@ bool ReFileSystem::first(const QString& pattern, ReFileMetaData& file) {
        QStringList names;
        names.append(pattern);
        ReIncludeExcludeMatcher matcher(names, ReQStringUtils::m_emptyList,
-           Qt::CaseInsensitive, true);
+               Qt::CaseInsensitive, true);
        listInfos(matcher, list);
        bool rc = list.size() > 0;
        if (rc)
@@ -146,12 +162,13 @@ void ReFileSystem::setBlocksize(int blocksize) {
  * @param logger
  */
 ReLocalFileSytem::ReLocalFileSytem(const QString& basePath, ReLogger* logger) :
-           ReFileSystem("localfs", logger),
-           m_basePath(basePath),
-           m_currentPath(basePath),
-           m_dir(basePath),
-           m_readFile(NULL),
-           m_writeFile(NULL) {
+               ReFileSystem("localfs", logger),
+               m_basePath(basePath),
+               m_dir(basePath),
+               m_readFile(NULL),
+               m_writeFile(NULL) {
+       m_directory = basePath;
+       ReQStringUtils::ensureLastChar(m_directory, OS_SEPARATOR);
        setWriteable(true);
 }
 
@@ -185,15 +202,6 @@ void ReLocalFileSytem::close() {
        }
 }
 
-/**
- * Returns the name of the current directory.
- *
- * @return     the name of the current directory
- */
-const QString& ReLocalFileSytem::directory() const {
-       return m_currentPath;
-}
-
 /**
  * Fills a list with the items of the current directory.
  *
@@ -201,13 +209,13 @@ const QString& ReLocalFileSytem::directory() const {
  * @return                     the count of the found entries (<code>list.size()</code>)
  */
 int ReLocalFileSytem::listInfos(const ReIncludeExcludeMatcher& matcher,
-    ReFileMetaDataList& list) {
+       ReFileMetaDataList& list) {
        list.clear();
        const QStringList& patterns = matcher.includes().patterns();
        QStringList nodes =
-           patterns.size() == 0 ? m_dir.entryList() : m_dir.entryList(patterns);
+               patterns.size() == 0 ? m_dir.entryList() : m_dir.entryList(patterns);
        QStringList::const_iterator it;
-       QByteArray full = m_currentPath.toUtf8();
+       QByteArray full = m_directory.toUtf8();
        full.append(OS_SEPARATOR);
        int pathLength = full.length();
        struct stat info;
@@ -217,9 +225,9 @@ int ReLocalFileSytem::listInfos(const ReIncludeExcludeMatcher& matcher,
                full.append(node.toUtf8());
                if (stat(full.constData(), &info) == 0) {
                        list.append(
-                           ReFileMetaData(node, QDateTime::fromTime_t(info.st_mtime),
-                               QDateTime::fromTime_t(info.st_ctime), info.st_uid,
-                               info.st_gid, info.st_mode, info.st_size));
+                               ReFileMetaData(node, QDateTime::fromTime_t(info.st_mtime),
+                                       QDateTime::fromTime_t(info.st_ctime), info.st_uid,
+                                       info.st_gid, info.st_mode, info.st_size));
                }
        }
        return list.size();
@@ -239,11 +247,11 @@ ReFileSystem::ErrorCode ReLocalFileSytem::makeDir(const QString& node) {
                rc = EC_FS_READ_ONLY;
        } else if (m_dir.exists(node)) {
                m_logger->logv(LOG_ERROR, LOC_MAKE_DIR_2, "node exists already: %s",
-                   fullNameAsUTF8(node).constData());
+                       fullNameAsUTF8(node).constData());
                rc = EC_ALREADY_EXISTS;
        } else if (!m_dir.mkdir(node)) {
                m_logger->logv(LOG_ERROR, LOC_MAKE_DIR_2, "cannot create directory: %s",
-                   fullNameAsUTF8(node).constData());
+                       fullNameAsUTF8(node).constData());
                rc = EC_NOT_ACCESSIBLE;
        }
        return rc;
@@ -259,7 +267,8 @@ ReFileSystem::ErrorCode ReLocalFileSytem::makeDir(const QString& node) {
  */
 ReFileSystem::ErrorCode ReLocalFileSytem::setDirectory(const QString& path) {
        ErrorCode rc = m_dir.setCurrent(path) ? EC_SUCCESS : EC_PATH_NOT_FOUND;
-       m_currentPath = m_dir.absolutePath();
+       m_directory = m_dir.absolutePath();
+       ReQStringUtils::ensureLastChar(m_directory, OS_SEPARATOR);
        return rc;
 }
 
@@ -275,16 +284,16 @@ ReFileSystem::ErrorCode ReLocalFileSytem::setDirectory(const QString& path) {
  *                                     EC_READ: error while reading
  */
 ReFileSystem::ErrorCode ReLocalFileSytem::read(const ReFileMetaData& source,
-    int64_t offset, int size, QByteArray& buffer) {
+       int64_t offset, int size, QByteArray& buffer) {
        ErrorCode rc = EC_SUCCESS;
        if (offset == 0) {
                if (m_readFile != NULL)
                        fclose(m_readFile);
-               QString fn = m_currentPath + source.m_node;
+               QString fn = fullName(source.m_node);
                if ((m_readFile = fopen(fn.toUtf8().constData(), "rb")) == NULL) {
                        m_logger->logv(LOG_ERROR, LOC_READ_1,
-                           "cannot open for reading (%d): %s", errno,
-                           fn.toUtf8().constData());
+                               "cannot open for reading (%d): %s", errno,
+                               fn.toUtf8().constData());
                        rc = EC_NOT_READABLE;
                }
        }
@@ -294,7 +303,7 @@ ReFileSystem::ErrorCode ReLocalFileSytem::read(const ReFileMetaData& source,
                int nRead = fread(buffer.data(), 1, size, m_readFile);
                if (nRead < 0) {
                        m_logger->logv(LOG_ERROR, LOC_READ_2, "cannot read (%d): %s", errno,
-                           source.m_node.toUtf8().constData());
+                               source.m_node.toUtf8().constData());
                        nRead = 0;
                        rc = EC_READ;
                }
@@ -326,21 +335,21 @@ ReFileSystem::ErrorCode ReLocalFileSytem::remove(const ReFileMetaData& node) {
                rc = EC_FS_READ_ONLY;
        } else if (!m_dir.exists(node.m_node)) {
                m_logger->logv(LOG_ERROR, LOC_REMOVE_2, "node does not exists: %s",
-                   fullNameAsUTF8(node.m_node).constData());
+                       fullNameAsUTF8(node.m_node).constData());
                rc = EC_NOT_EXISTS;
        } else {
                if (S_ISDIR(node.m_mode)) {
                        if (!m_dir.rmdir(node.m_node)) {
                                m_logger->logv(LOG_ERROR, LOC_REMOVE_3,
-                                   "cannot remove directory: %s",
-                                   fullNameAsUTF8(node.m_node).constData());
+                                       "cannot remove directory: %s",
+                                       fullNameAsUTF8(node.m_node).constData());
                                rc = EC_NOT_ACCESSIBLE;
                        }
                } else {
                        if (!m_dir.remove(node.m_node)) {
                                m_logger->logv(LOG_ERROR, LOC_REMOVE_3,
-                                   "cannot remove file: %s",
-                                   fullNameAsUTF8(node.m_node).constData());
+                                       "cannot remove file: %s",
+                                       fullNameAsUTF8(node.m_node).constData());
                                rc = EC_NOT_ACCESSIBLE;
                        }
                }
@@ -353,6 +362,8 @@ ReFileSystem::ErrorCode ReLocalFileSytem::remove(const ReFileMetaData& node) {
  *
  * @param source       the properties to copy
  * @param target       the properties of the file to change
+ * @param force                <code>true</code>: try to change rights to enable other changes<br>
+ *                                     <code>false</code>: current rights will be respected
  * @return                     EC_SUCCESS: successful<br>
  *                                     EC_FS_READ_ONLY: filesystem is readonly<br>
  *                                     EC_ALREADY_EXISTS: renaming failed: target node exists already<br>
@@ -360,53 +371,67 @@ ReFileSystem::ErrorCode ReLocalFileSytem::remove(const ReFileMetaData& node) {
  *
  */
 ReFileSystem::ErrorCode ReLocalFileSytem::setProperties(
-    const ReFileMetaData& source, const ReFileMetaData& target) {
+       const ReFileMetaData& source, ReFileMetaData& target,
+               bool force) {
        ErrorCode rc = EC_SUCCESS;
        if (!m_writeable) {
                m_logger->log(LOG_ERROR, LOC_SET_PROPERTIES_1,
-                   "filesystem is readonly");
+                       "filesystem is readonly");
                rc = EC_FS_READ_ONLY;
        } else
                do {
-                       if (target.m_node != source.m_node) {
+                       QByteArray name;
+                       bool nameChanged = target.m_node != source.m_node;
+                       bool timeChanged = source.m_modified != target.m_modified
+                               && source.m_modified != ReFileUtils::m_undefinedTime;
+#ifdef __linux__
+               bool modeChanged = (source.m_mode & ALLPERMS) != (target.m_mode & ALLPERMS)
+                               && source.m_mode != (mode_t) -1;
+               bool ownerChanged = (source.m_owner != target.m_owner
+                               && source.m_owner != -1)
+                       || (source.m_group != source.m_group
+                               && source.m_group != -1);
+               if (force && m_uid != 0 && (nameChanged || timeChanged || modeChanged
+                                                                       || ownerChanged)){
+                       name = fullNameAsUTF8(target.m_node);
+                       chmod(name.constData(), ALLPERMS);
+                       modeChanged = true;
+               }
+
+#endif
+                       if (nameChanged) {
                                if (m_dir.exists(source.m_node)) {
+                                       if (name.length() == 0)
+                                               name = fullNameAsUTF8(target.m_node);
                                        rc = EC_ALREADY_EXISTS;
                                        m_logger->logv(LOG_ERROR, LOC_SET_PROPERTIES_2,
-                                           "renaming impossible: node exists: %s",
-                                           fullNameAsUTF8(target.m_node).constData());
+                                               "renaming impossible: node exists: %s",
+                                               name.constData());
                                        break;
                                } else if (!m_dir.rename(target.m_node, source.m_node)) {
                                        rc = EC_RENAME;
+                                       if (name.length() == 0)
+                                               name = fullNameAsUTF8(target.m_node);
                                        m_logger->logv(LOG_ERROR, LOC_SET_PROPERTIES_3,
-                                           "renaming impossible: %s -> %s",
-                                           source.m_node.toUtf8().constData(),
-                                           fullNameAsUTF8(target.m_node).constData());
+                                               "renaming impossible: %s -> %s",
+                                               source.m_node.toUtf8().constData(),
+                                               name.constData());
                                        break;
+                               } else {
+                                       name.resize(0);
+                                       target.m_node = source.m_node;
                                }
                        }
-                       QByteArray name;
-                       if (source.m_modified != target.m_modified
-                           && source.m_modified != ReFileUtils::m_undefinedTime) {
+                       if (timeChanged) {
                                if (name.length() == 0)
                                        name = fullNameAsUTF8(target.m_node);
                                if (!ReFileUtils::setTimes(name.constData(), source.m_modified,
-                                   ReFileUtils::m_undefinedTime, m_logger))
+                                       ReFileUtils::m_undefinedTime, m_logger))
                                        rc = EC_NOT_ACCESSIBLE;
 
                        }
 #ifdef __linux__
-                       if (source.m_mode != target.m_mode
-                               && source.m_mode != (mode_t) -1) {
-                               if (chmod(name.constData(), source.m_mode) != 0) {
-                                       rc = EC_NOT_ACCESSIBLE;
-                                       m_logger->logv(LOG_ERROR, LOC_SET_PROPERTIES_4,
-                                               "changing permissions is impossible: %s",
-                                               name.constData());}
-                       }
-                       if ( (source.m_owner != target.m_owner
-                                       && source.m_owner != -1)
-                               || (source.m_group != source.m_group
-                                       && source.m_group != -1)) {
+                       if (ownerChanged) {
                                int uid = source.m_owner == -1 ? target.m_owner : source.m_owner;
                                int gid = source.m_group == -1 ? target.m_group : source.m_group;
                                if (name.length() == 0)
@@ -418,6 +443,15 @@ ReFileSystem::ErrorCode ReLocalFileSytem::setProperties(
                                                name.constData());
                                }
                        }
+                       if (modeChanged) {
+                               mode_t mode = source.m_mode == (mode_t) -1
+                                               ? target.m_mode : source.m_mode;
+                               if (chmod(name.constData(), mode & ALLPERMS) != 0) {
+                                       rc = EC_NOT_ACCESSIBLE;
+                                       m_logger->logv(LOG_ERROR, LOC_SET_PROPERTIES_4,
+                                               "changing permissions is impossible: %s",
+                                               name.constData());}
+                       }
 #endif
                } while (false);
        return rc;
@@ -437,7 +471,7 @@ ReFileSystem::ErrorCode ReLocalFileSytem::setProperties(
  *
  */
 ReFileSystem::ErrorCode ReLocalFileSytem::write(const QString& node,
-    int64_t offset, const QByteArray& buffer) {
+       int64_t offset, const QByteArray& buffer) {
        ErrorCode rc = EC_SUCCESS;
        if (!writeable()) {
                m_logger->log(LOG_ERROR, LOC_WRITE_1, "filesystem is readonly");
@@ -446,11 +480,11 @@ ReFileSystem::ErrorCode ReLocalFileSytem::write(const QString& node,
                if (offset == 0) {
                        if (m_writeFile != NULL)
                                fclose(m_writeFile);
-                       QString fn = m_currentPath + node;
+                       QString fn = fullName(node);
                        if ((m_writeFile = fopen(fn.toUtf8().constData(), "wb")) == NULL) {
                                m_logger->logv(LOG_ERROR, LOC_WRITE_2,
-                                   "cannot open for writing (%d): %s", errno,
-                                   fn.toUtf8().constData());
+                                       "cannot open for writing (%d): %s", errno,
+                                       fn.toUtf8().constData());
                                rc = EC_NOT_WRITEABLE;
                        }
                }
@@ -459,14 +493,14 @@ ReFileSystem::ErrorCode ReLocalFileSytem::write(const QString& node,
                        if (position != offset) {
                                rc = EC_POSITION;
                                m_logger->logv(LOG_ERROR, LOC_WRITE_4,
-                                   "wrong file position: %lld/%lld", offset, position);
+                                       "wrong file position: %lld/%lld", offset, position);
                        } else {
                                int nWritten = fwrite(buffer.constData(), 1, buffer.length(),
-                                   m_writeFile);
+                                       m_writeFile);
                                if (nWritten != buffer.length()) {
                                        m_logger->logv(LOG_ERROR, LOC_WRITE_3,
-                                           "cannot write (%d): %s written: %d/%d", errno,
-                                           node.toUtf8().constData(), nWritten, buffer.length());
+                                               "cannot write (%d): %s written: %d/%d", errno,
+                                               node.toUtf8().constData(), nWritten, buffer.length());
                                        rc = EC_WRITE;
                                }
                                fflush(m_writeFile);
@@ -480,13 +514,13 @@ ReFileSystem::ErrorCode ReLocalFileSytem::write(const QString& node,
  * Constructor.
  */
 ReFileMetaData::ReFileMetaData() :
-           m_node(),
-           m_modified(),
-           m_created(),
-           m_owner(-1),
-           m_group(-1),
-           m_mode(-1),
-           m_size(-1) {
+               m_node(),
+               m_modified(),
+               m_created(),
+               m_owner(-1),
+               m_group(-1),
+               m_mode(-1),
+               m_size(-1) {
 
 }
 
@@ -502,14 +536,14 @@ ReFileMetaData::ReFileMetaData() :
  * @param size         the filesize (0 for directories)
  */
 ReFileMetaData::ReFileMetaData(const QString& node, const QDateTime& modified,
-    const QDateTime& created, int owner, int group, mode_t mode, int64_t size) :
-           m_node(node),
-           m_modified(modified),
-           m_created(created),
-           m_owner(owner),
-           m_group(group),
-           m_mode(mode),
-           m_size(size) {
+       const QDateTime& created, int owner, int group, mode_t mode, int64_t size) :
+               m_node(node),
+               m_modified(modified),
+               m_created(created),
+               m_owner(owner),
+               m_group(group),
+               m_mode(mode),
+               m_size(size) {
 
 }
 
@@ -525,13 +559,13 @@ ReFileMetaData::~ReFileMetaData() {
  * @param source       source to copy
  */
 ReFileMetaData::ReFileMetaData(const ReFileMetaData& source) :
-           m_node(source.m_node),
-           m_modified(source.m_modified),
-           m_created(source.m_created),
-           m_owner(source.m_owner),
-           m_group(source.m_group),
-           m_mode(source.m_mode),
-           m_size(source.m_size) {
+               m_node(source.m_node),
+               m_modified(source.m_modified),
+               m_created(source.m_created),
+               m_owner(source.m_owner),
+               m_group(source.m_group),
+               m_mode(source.m_mode),
+               m_size(source.m_size) {
 
 }
 
index cfaee4b9fe665c6347cdd49aa0b2476119af9d24..425f38bd0651ae32b834589fde5406b9295a1380 100644 (file)
@@ -16,8 +16,9 @@ class ReFileMetaData {
 public:
        ReFileMetaData();
        ReFileMetaData(const QString& node, const QDateTime& modified,
-           const QDateTime& created, int owner, int group, mode_t mode,
-           int64_t size);
+               const QDateTime& created,
+               int owner = -1, int group = -1,
+               mode_t mode = (mode_t) -1, int64_t size = 0);
        virtual ~ReFileMetaData();
        ReFileMetaData(const ReFileMetaData& source);
        ReFileMetaData& operator =(const ReFileMetaData& source);
@@ -67,13 +68,13 @@ public:
        /** Returns the name of the current directory.
         * @return      the name of the current directory
         */
-       virtual const QString& directory() const = 0;
+       virtual const QString& directory() const;
        /** Fills a list with the items of the current directory.
         * @param matcher       the matching processor
         * @return                      the count of the found entries (<code>list.size()</code>)
         */
        virtual int listInfos(const ReIncludeExcludeMatcher& matcher,
-           ReFileMetaDataList& list) = 0;
+               ReFileMetaDataList& list) = 0;
        /** Creates a directory.
         * @param node  the name without path (in the current directory)
         * @return              EC_SUCCESS or error code
@@ -87,7 +88,7 @@ public:
         * @return                      EC_SUCCESS or error code
         */
        virtual ErrorCode read(const ReFileMetaData& source, int64_t offset,
-           int size, QByteArray& buffer) = 0;
+               int size, QByteArray& buffer) = 0;
        /** Removes a file or directory.
         * @param node  the properties ot the node (in the current directory)
         * @return              EC_SUCCESS or error code
@@ -102,10 +103,13 @@ public:
        /** Sets the properties of a file in the current directory.
         * @param source        the properties to copy
         * @param target        the properties of the file to change
-        * @return              EC_SUCCESS or error code
+        * @param force         <code>true</code>: try to change rights to enable
+        *                                      other changes<br>
+        *                                      <code>false</code>: current rights will be respected
+        * @return                      EC_SUCCESS or error code
         */
        virtual ErrorCode setProperties(const ReFileMetaData& source,
-           const ReFileMetaData& target) = 0;
+               ReFileMetaData& target, bool force) = 0;
        /** Writes a buffer to a file.
         * @param node          the file to write (without path, inside the current directory)
         * @param offset        first position to write
@@ -113,7 +117,7 @@ public:
         * @return                      EC_SUCCESS or error code
         */
        virtual ErrorCode write(const QString& target, int64_t offset,
-           const QByteArray& buffer) = 0;
+               const QByteArray& buffer) = 0;
 public:
        virtual ErrorCode copy(ReFileMetaData& source, ReFileSystem& sourceFS);
 public:
@@ -139,6 +143,11 @@ public:
 
 protected:
        QString m_name;
+#ifdef __linux__
+       int m_uid;
+       int m_gid;
+#endif
+       // ending with OS_SEPARATOR:
        QString m_directory;
        bool m_writeable;
        ReLogger* m_logger;
@@ -153,28 +162,25 @@ public:
        virtual ~ReLocalFileSytem();
 public:
        const QString& basePath() const;
-       const QString& directory() const;
        ErrorCode setDirectory(const QString& path);
 
 public:
        // ReFileSystem interface
        virtual void close();
        virtual int listInfos(const ReIncludeExcludeMatcher& matcher,
-           ReFileMetaDataList& list);
+               ReFileMetaDataList& list);
        ErrorCode makeDir(const QString& node);
        virtual ErrorCode read(const ReFileMetaData& source, int64_t offset,
-           int size, QByteArray& buffer);
+               int size, QByteArray& buffer);
        ErrorCode remove(const ReFileMetaData& node);
        ErrorCode setProperties(const ReFileMetaData& source,
-           const ReFileMetaData& target);
+               ReFileMetaData& target, bool force = false);
        virtual ErrorCode write(const QString& target, int64_t offset,
-           const QByteArray& buffer);
+               const QByteArray& buffer);
 
 protected:
        QString m_basePath;
-       QString m_currentPath;
        QDir m_dir;
-
        FILE* m_readFile;
        FILE* m_writeFile;