From: hama Date: Sun, 27 Sep 2015 09:10:43 +0000 (+0200) Subject: some methods moved from ReQStringUtils to ReFileUtils X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=7aeb1383b00aea4b77cd10db5ec66c628f9deaf1;p=reqt some methods moved from ReQStringUtils to ReFileUtils --- diff --git a/base/ReFileUtils.cpp b/base/ReFileUtils.cpp index 314d22b..1f86781 100644 --- a/base/ReFileUtils.cpp +++ b/base/ReFileUtils.cpp @@ -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 base) + * @return path if it is an absolute path
+ * 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 base) + * @return path if it is an absolute path
+ * 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
+ * otherwise: the extension of filename + */ +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
+ * otherwise: the extension of filename + */ +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 filename + */ +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 filename + */ +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. diff --git a/base/ReFileUtils.hpp b/base/ReFileUtils.hpp index ebbc48b..3b27636 100644 --- a/base/ReFileUtils.hpp +++ b/base/ReFileUtils.hpp @@ -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, diff --git a/base/ReQStringUtils.cpp b/base/ReQStringUtils.cpp index d605a46..9d816f5 100644 --- a/base/ReQStringUtils.cpp +++ b/base/ReQStringUtils.cpp @@ -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
- * otherwise: the extension of filename - */ -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 filename - */ -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 base) - * @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. * diff --git a/base/ReQStringUtils.hpp b/base/ReQStringUtils.hpp index e0e4934..b883cb3 100644 --- a/base/ReQStringUtils.hpp +++ b/base/ReQStringUtils.hpp @@ -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& placeholders, QString* error); static void skipExpected(const ReString& text, QChar expected, int& index, diff --git a/cunit/cuReFileSystem.cpp b/cunit/cuReFileSystem.cpp index 2ed6ad6..39abdcb 100644 --- a/cunit/cuReFileSystem.cpp +++ b/cunit/cuReFileSystem.cpp @@ -18,22 +18,22 @@ 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(); } }; diff --git a/cunit/cuReFileUtils.cpp b/cunit/cuReFileUtils.cpp index 2b033c1..c3d21e4 100644 --- a/cunit/cuReFileUtils.cpp +++ b/cunit/cuReFileUtils.cpp @@ -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(); diff --git a/cunit/cuReQStringUtils.cpp b/cunit/cuReQStringUtils.cpp index 0711f78..cdfa81f 100644 --- a/cunit/cuReQStringUtils.cpp +++ b/cunit/cuReQStringUtils.cpp @@ -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'); diff --git a/os/ReFileSystem.cpp b/os/ReFileSystem.cpp index 9f23df3..06c819d 100644 --- a/os/ReFileSystem.cpp +++ b/os/ReFileSystem.cpp @@ -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 (list.size()) */ 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 true: try to change rights to enable other changes
+ * false: current rights will be respected * @return EC_SUCCESS: successful
* EC_FS_READ_ONLY: filesystem is readonly
* EC_ALREADY_EXISTS: renaming failed: target node exists already
@@ -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) { } diff --git a/os/ReFileSystem.hpp b/os/ReFileSystem.hpp index cfaee4b..425f38b 100644 --- a/os/ReFileSystem.hpp +++ b/os/ReFileSystem.hpp @@ -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 (list.size()) */ 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 true: try to change rights to enable + * other changes
+ * false: 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;