From e5988c7d648676390d8ec2098fe1d629a84c0953 Mon Sep 17 00:00:00 2001 From: hama Date: Tue, 24 Nov 2015 00:14:09 +0100 Subject: [PATCH] ReLeafFile implementation --- appl/resh/.gitignore | 73 +++++++++ appl/resh/ReShellTree.cpp | 16 ++ appl/resh/ReShellTree.hpp | 74 +++++++++ appl/resh/main.cpp | 18 +++ appl/resh/resh.hpp | 18 +++ appl/resh/resh.pro | 26 ++++ cunit/cuReFileSystem.cpp | 28 +++- os/ReCryptFileSystem.cpp | 103 ++++++++++++- os/ReCryptFileSystem.hpp | 21 ++- os/ReFileSystem.cpp | 314 ++++++++++++++++++++++---------------- os/ReFileSystem.hpp | 151 ++++++++++++++---- 11 files changed, 675 insertions(+), 167 deletions(-) create mode 100644 appl/resh/.gitignore create mode 100644 appl/resh/ReShellTree.cpp create mode 100644 appl/resh/ReShellTree.hpp create mode 100644 appl/resh/main.cpp create mode 100644 appl/resh/resh.hpp create mode 100644 appl/resh/resh.pro diff --git a/appl/resh/.gitignore b/appl/resh/.gitignore new file mode 100644 index 0000000..5439c79 --- /dev/null +++ b/appl/resh/.gitignore @@ -0,0 +1,73 @@ +# This file is used to ignore files which are generated +# ---------------------------------------------------------------------------- + +*~ +*.autosave +*.a +*.core +*.moc +*.o +*.obj +*.orig +*.rej +*.so +*.so.* +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +!core/ +tags +.DS_Store +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp +Thumbs.db +*.res +*.rc +/.qmake.cache +/.qmake.stash + +# qtcreator generated files +*.pro.user* + +# xemacs temporary files +*.flc + +# Vim temporary files +.*.swp + +# Visual Studio generated files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* + +# MinGW generated files +*.Debug +*.Release + +# Python byte code +*.pyc + +# Binaries +# -------- +*.dll +*.exe + + diff --git a/appl/resh/ReShellTree.cpp b/appl/resh/ReShellTree.cpp new file mode 100644 index 0000000..6f8cce0 --- /dev/null +++ b/appl/resh/ReShellTree.cpp @@ -0,0 +1,16 @@ +/* + * Licence: + * You can use and modify this file without any restriction. + * There is no warranty. + * You also can use the licence from http://www.wtfpl.net/. + * The original sources can be found on https://github.com/republib. +*/ + + +#include "resh.hpp" + +ReShellTree::ReShellTree() +{ + +} + diff --git a/appl/resh/ReShellTree.hpp b/appl/resh/ReShellTree.hpp new file mode 100644 index 0000000..ab58302 --- /dev/null +++ b/appl/resh/ReShellTree.hpp @@ -0,0 +1,74 @@ +/* + * Licence: + * You can use and modify this file without any restriction. + * There is no warranty. + * You also can use the licence from http://www.wtfpl.net/. + * The original sources can be found on https://github.com/republib. +*/ + + +#ifndef RESHELLTREE_HPP +#define RESHELLTREE_HPP + +class ReShellStatement{ +public: + enum StatementFlags { + SF_UNDEF, + SF_INTERNAL_CMD = 1, + SF_VAR_EXPANSION = 2, + SF_INTERPOLATION = 4, + SF_INP_REDIRECT = 8, + SF_OUT_REDIRECT = 16, + SF_SHELL_SCRIPT = 32, + SF_OUT_TO_STRING = 64, + }; +public: + ReSource* source; + ReShellStatement* m_next; + int m_flags; +}; + +class ReShellIf : public ReShellStatement{ +public: + ReShellStatement* m_condition; + ReShellStatement* m_then; + ReShellStatement* m_else; +}; + +class ReShellWhile : public ReShellStatement{ +public: + ReShellStatement* m_condition; + ReShellStatement* m_body; +}; + +class ReCaseAlternative { +public: + QByteArray m_value; + ReShellStatement* m_statement; + ReCaseAlternative* m_next; +}; + + +class ReShellCase : public ReShellStatement{ +protected: + ReCaseAlternative* m_condition; + ReShellStatement* m_body; +}; + +class ReShellFunction { +public: + QByteArray m_name; + ReShellStatement* m_body; +}; + + +class ReShellTree +{ +public: + ReShellTree(); +public: + QList m_functions; + ReShellStatement m_body; +}; + +#endif // RESHELLTREE_HPP diff --git a/appl/resh/main.cpp b/appl/resh/main.cpp new file mode 100644 index 0000000..8a70156 --- /dev/null +++ b/appl/resh/main.cpp @@ -0,0 +1,18 @@ +/* + * Licence: + * You can use and modify this file without any restriction. + * There is no warranty. + * You also can use the licence from http://www.wtfpl.net/. + * The original sources can be found on https://github.com/republib. +*/ + + +#include + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + + return a.exec(); +} + diff --git a/appl/resh/resh.hpp b/appl/resh/resh.hpp new file mode 100644 index 0000000..6bfb778 --- /dev/null +++ b/appl/resh/resh.hpp @@ -0,0 +1,18 @@ +/* + * Licence: + * You can use and modify this file without any restriction. + * There is no warranty. + * You also can use the licence from http://www.wtfpl.net/. + * The original sources can be found on https://github.com/republib. +*/ + + +#ifndef RESH_HPP +#define RESH_HPP + +#include "base/rebase.hpp" +#include "expr/reexpr.hpp" +#include "os/reos.hpp" +#include "ReShellTree.hpp" +#endif // RESH_HPP + diff --git a/appl/resh/resh.pro b/appl/resh/resh.pro new file mode 100644 index 0000000..03707b3 --- /dev/null +++ b/appl/resh/resh.pro @@ -0,0 +1,26 @@ +QT += core +#QT -= gui +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = resh +CONFIG += console +CONFIG -= app_bundle + +TEMPLATE = app + +INCLUDEPATH = ../.. + +SOURCES += main.cpp \ + ../../base/ReStringUtils.cpp \ + ../../base/ReQStringUtils.cpp \ + ../../base/ReCharPtrMap.cpp \ + ../../base/ReException.cpp \ + ../../base/ReLogger.cpp \ + ../../expr/ReSource.cpp \ + ../../expr/ReLexer.cpp \ + ReShellTree.cpp +# ../../expr/ReExpression.cpp \ + +HEADERS += \ + resh.hpp + diff --git a/cunit/cuReFileSystem.cpp b/cunit/cuReFileSystem.cpp index 6c0da08..b1fce07 100644 --- a/cunit/cuReFileSystem.cpp +++ b/cunit/cuReFileSystem.cpp @@ -67,21 +67,39 @@ protected: ReLocalFileSystem fs(m_base, &m_logger); QByteArray buffer; buffer.append("abcdefghijklmnopqrstuvwxyz"); - checkEqu(0, fs.write("abc.txt", 0LL, buffer)); - checkEqu(0, fs.write("abc.txt", 26LL, buffer)); + + //checkEqu(0, fs.write("abc.txt", 0LL, buffer)); + //checkEqu(0, fs.write("abc.txt", 26LL, buffer)); QByteArray buffer2; ReFileMetaDataList nodes; QStringList names; names.append("abc.txt"); + names.append("new.txt"); ReIncludeExcludeMatcher matcher(names, ReQStringUtils::m_emptyList, Qt::CaseInsensitive, true); checkEqu(1, fs.listInfos(matcher, nodes, ReFileSystem::LO_UNDEF)); checkEqu(1, nodes.size()); - checkEqu(0, fs.read(nodes.at(0), 0LL, 3, buffer2)); + QByteArray content("This is a content\nLine 2"); + checkEqu(0, fs.createFile("new.txt", false)); + ReFileMetaData meta; + checkT(fs.exists("new.txt", &meta)); + ReLeafFile* leaf1 = fs.buildFile(meta); + leaf1->open(true); + leaf1->write(content); + leaf1->close(); + delete leaf1; + checkT(fs.exists("new.txt", &meta)); + ReLeafFile* leaf2 = fs.buildFile(meta); + leaf2->open(false); + leaf2->read(500, buffer); + leaf2->close(); + delete leaf2; + + //checkEqu(0, fs.read(nodes.at(0), 0LL, 3, buffer2)); checkEqu("abc", buffer2); - checkEqu(0, fs.read(nodes.at(0), 3LL, 7, buffer2)); + //checkEqu(0, fs.read(nodes.at(0), 3LL, 7, buffer2)); checkEqu("defghij", buffer2); - checkEqu(0, fs.read(nodes.at(0), 10LL, 99, buffer2)); + //checkEqu(0, fs.read(nodes.at(0), 10LL, 99, buffer2)); checkEqu("klmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", buffer2); } void testSetProperties() { diff --git a/os/ReCryptFileSystem.cpp b/os/ReCryptFileSystem.cpp index 99e4096..f41c1d9 100644 --- a/os/ReCryptFileSystem.cpp +++ b/os/ReCryptFileSystem.cpp @@ -49,6 +49,7 @@ enum { LOC_MAKE_DIR_1, // 12308 LOC_FILE_OPEN_1, // 12309 LOC_FILE_WRITE_1, // 12310 + LOC_CREATE_FILE_1, // 12311 }; const int ReCryptFileSystem::NODE_LENGHT = 44; @@ -95,15 +96,67 @@ ReCryptFileSystem::ReCryptFileSystem(ReFileSystem& hostFileSystem, ReCryptFileSystem::~ReCryptFileSystem() { } +/** + * Returns a filesystem dependent instance of a file. + * + * The file must exist in the current directory. + * The caller must free the instance. + * + * @param meta the metadata of the file + * @return NULL: no file found
+ * otherwise: the file + */ +ReLeafFile* ReCryptFileSystem::buildFile(const ReFileMetaData& metadata) +{ + return new ReCryptLeafFile(metadata, fullName(metadata.m_node), m_logger2); +} + QString ReCryptFileSystem::canonicalPathOf(const QString& path) { return ReFileUtils::cleanPath(path); } -/** Frees resources like open files. +/** + * Creates a new file in the current directory. + * + * @param node the name of the new file + * @param inDirectoryOnly false: the file is made physically
+ * otherwise: the file exists only in the metadata + * of the directory + * @param metadata OUT: NULL or the metadata of the new file + * @return EC_SUCCESS: success
+ * EC_ALREADY_EXISTS: the file already exists + * EC_WRITE: the file could not be written */ -void ReCryptFileSystem::close() +ReFileSystem::ErrorCode ReCryptFileSystem::createFile(const QString& node, + bool inDirectoryOnly, ReFileMetaData* metadata) { + ErrorCode rc = EC_SUCCESS; + if (exists(node, NULL)) + rc = EC_ALREADY_EXISTS; + else{ + QDateTime now = QDateTime::currentDateTime(); + int id = ++m_maxFileId; + ReFileMetaData meta = ReFileMetaData(node, now, now, + m_osPermissions.m_user, m_osPermissions.m_group, + m_osPermissions.m_dirMode, 0, id); + m_list.append(meta); + if (metadata != NULL){ + *metadata = meta; + } + if (! inDirectoryOnly){ + QString hostName = buildHostedNode(id); + QByteArray fullName = fullNameAsUTF8(hostName); + FILE* fp = fopen(fullName.constData(), "w"); + if (fp == NULL){ + rc = EC_WRITE; + m_logger2->logv(LOG_ERROR, LOC_CREATE_FILE_1, "cannot open (%d): %s", + errno, fullName.constData()); + } else + fclose(fp); + } + } + return rc; } /** @@ -830,3 +883,49 @@ ReFileSystem::ErrorCode ReCryptFile::close() } return rc; } + +/** + * Constructor. + * + * @param metaData metadata of the file + * @param fullName filename with path + * @param logger the logger + */ +ReCryptLeafFile::ReCryptLeafFile(const ReFileMetaData& metaData, + const QString& fullName, ReLogger* logger) : + ReLeafFile(metaData, fullName, logger) +{ + +} + +/** + * Destructor. + */ +ReCryptLeafFile::~ReCryptLeafFile() +{ + +} + +ReFileSystem::ErrorCode ReCryptLeafFile::open(bool writeable) +{ + ReFileSystem::ErrorCode rc = ReFileSystem::EC_SUCCESS; + return rc; +} + +ReFileSystem::ErrorCode ReCryptLeafFile::close() +{ + ReFileSystem::ErrorCode rc = ReFileSystem::EC_SUCCESS; + return rc; +} + +ReFileSystem::ErrorCode ReCryptLeafFile::read(int size, QByteArray& buffer) +{ + ReFileSystem::ErrorCode rc = ReFileSystem::EC_SUCCESS; + return rc; +} + +ReFileSystem::ErrorCode ReCryptLeafFile::write(const QByteArray& buffer) +{ + ReFileSystem::ErrorCode rc = ReFileSystem::EC_SUCCESS; + return rc; +} diff --git a/os/ReCryptFileSystem.hpp b/os/ReCryptFileSystem.hpp index 45ed45d..5ede305 100644 --- a/os/ReCryptFileSystem.hpp +++ b/os/ReCryptFileSystem.hpp @@ -110,6 +110,23 @@ protected: int m_maxFileId; }; +/** + * An abstract base class for leafs of the tree spanned by a filesystem. + * + * A leaf file could not be a directory. + */ +class ReCryptLeafFile : public ReLeafFile{ +public: + ReCryptLeafFile(const ReFileMetaData& metaData, const QString& fullName, + ReLogger* logger); + virtual ~ReCryptLeafFile(); +public: + virtual ReFileSystem::ErrorCode open(bool writeable); + virtual ReFileSystem::ErrorCode close(); + virtual ReFileSystem::ErrorCode read(int size, QByteArray& buffer); + virtual ReFileSystem::ErrorCode write(const QByteArray& buffer); +}; + /** * A filesystem with encrypted filenames and file content. * @@ -134,8 +151,10 @@ public: ReRandomizer& contentRandom, ReLogger* logger); ~ReCryptFileSystem(); public: + virtual ReLeafFile* buildFile(const ReFileMetaData& metadata); virtual QString canonicalPathOf(const QString& path); - virtual void close(); + virtual ErrorCode createFile(const QString& node, bool inDirectoryOnly, + ReFileMetaData* metadata = NULL); virtual bool exists(const QString& node, ReFileMetaData* metaInfo) const; virtual int listInfos(const ReIncludeExcludeMatcher& matcher, ReFileMetaDataList& list, ListOptions options = LO_ALL); diff --git a/os/ReFileSystem.cpp b/os/ReFileSystem.cpp index 9e87349..962256f 100644 --- a/os/ReFileSystem.cpp +++ b/os/ReFileSystem.cpp @@ -30,6 +30,8 @@ enum { LOC_REMOVE_3, // 12015 LOC_SET_PROPERTIES_4, // 12016 LOC_SET_PROPERTIES_5, // 12017 + LOC_OPEN_1, // 12018 + LOC_CREATE_FILE_1, // 12019 }; /** @@ -101,19 +103,32 @@ ReFileSystem::ErrorCode ReFileSystem::copy(ReFileMetaData& source, 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) - rc = rc2; - else if ((rc2 = write(source.m_node, size, m_buffer)) != EC_SUCCESS) - rc = rc2; - size += blocksize; + ReLeafFile* sourceFile = sourceFS.buildFile(source); + ReFileMetaData targetMeta; + if (! exists(source.m_node, &targetMeta)){ + rc = createFile(source.m_node, false, &targetMeta); + } + if (rc == EC_SUCCESS){ + ReLeafFile* targetFile = buildFile(targetMeta); + if (sourceFile->open(false) == EC_SUCCESS + && targetFile->open(true) == EC_SUCCESS){ + while (rc == EC_SUCCESS && size < source.m_size) { + if ((rc2 = sourceFile->read(blocksize, m_buffer)) + != EC_SUCCESS) + rc = rc2; + else if ((rc2 = targetFile->write(m_buffer)) != EC_SUCCESS) + rc = rc2; + size += blocksize; + } + } + sourceFile->close(); + targetFile->close(); + ReFileMetaData target(source.m_node, ReFileUtils::m_undefinedTime, + ReFileUtils::m_undefinedTime, m_uid, m_gid); + setProperties(source, target, false); + delete sourceFile; + delete targetFile; } - close(); - sourceFS.close(); - ReFileMetaData target(source.m_node, ReFileUtils::m_undefinedTime, - ReFileUtils::m_undefinedTime, m_uid, m_gid); - setProperties(source, target, false); return rc; } @@ -330,9 +345,7 @@ bool ReFileSystem::writeable() const { ReLocalFileSystem::ReLocalFileSystem(const QString& basePath, ReLogger* logger) : ReFileSystem("localfs", logger), m_basePath(basePath), - m_dir(basePath), - m_readFile(NULL), - m_writeFile(NULL) { + m_dir(basePath) { m_directory = basePath; ReQStringUtils::ensureLastChar(m_directory, OS_SEPARATOR); setWriteable(true); @@ -354,20 +367,6 @@ const QString& ReLocalFileSystem::basePath() const { return m_basePath; } -/** - * Closes the open files. - */ -void ReLocalFileSystem::close() { - if (m_readFile != NULL) { - fclose(m_readFile); - m_readFile = NULL; - } - if (m_writeFile != NULL) { - fclose(m_writeFile); - m_writeFile = NULL; - } -} - /** * Search a file in the current directory given by name. * @@ -498,6 +497,44 @@ ReFileSystem::ErrorCode ReLocalFileSystem::setDirectory(const QString& path) { return rc; } +/** + * Creates a new file in the current directory. + * + * @param node the name of the new file + * @param inDirectoryOnly false: the file is made physically
+ * otherwise: the file exists only in the metadata + * of the directory + * @param metadata OUT: NULL or the metadata of the new file + * @return EC_SUCCESS: success
+ * EC_ALREADY_EXISTS: the file already exists + * EC_WRITE: the file could not be written + */ +ReFileSystem::ErrorCode ReLocalFileSystem::createFile(const QString& node, + bool inDirectoryOnly, ReFileMetaData* metadata) +{ + ErrorCode rc = EC_SUCCESS; + if (exists(node)) + rc = EC_ALREADY_EXISTS; + else{ + if (metadata != NULL){ + QDateTime now = QDateTime::currentDateTime(); + *metadata = ReFileMetaData(node, now, now, m_osPermissions.m_user, + m_osPermissions.m_group, m_osPermissions.m_dirMode, 0); + } + if (! inDirectoryOnly){ + QByteArray name(fullNameAsUTF8(node)); + FILE* fp = fopen(name.constData(), "w"); + if (fp == NULL){ + rc = EC_WRITE; + m_logger->logv(LOG_ERROR, LOC_CREATE_FILE_1, "cannot open (%d): %s", + errno, name.constData()); + } else + fclose(fp); + } + } + return rc; +} + /** * Returns the canonical form of a given path. * @@ -512,52 +549,6 @@ QString ReLocalFileSystem::canonicalPathOf(const QString& path) return rc; } -/** - * Reads a part of a file into a buffer. - * - * @param source the file to move - * @param offset first position to read - * @param size number of bytes to read - * @param buffer OUT: content of the file - * @return EC_SUCCESS: success
- * EC_NOT_READABLE: file can't be opened
- * EC_READ: error while reading - */ -ReFileSystem::ErrorCode ReLocalFileSystem::read(const ReFileMetaData& source, - int64_t offset, int size, QByteArray& buffer) { - ErrorCode rc = EC_SUCCESS; - if (offset == 0) { - if (m_readFile != NULL) - fclose(m_readFile); - 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()); - rc = EC_NOT_READABLE; - } - } - if (m_readFile != NULL) { - ReFileUtils::seek(m_readFile, offset, SEEK_SET); - buffer.reserve(size); - 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()); - nRead = 0; - rc = EC_READ; - } - buffer.resize(nRead); - if (feof(m_readFile)) { - fclose(m_readFile); - m_readFile = NULL; - } else { - fflush(m_readFile); - } - } - return rc; -} - /** * Removes a file or directory. * @@ -695,59 +686,6 @@ ReFileSystem::ErrorCode ReLocalFileSystem::setProperties( return rc; } -/** - * Writes a buffer to a file. - * - * @param node the file to write (without path, inside the current directory) - * @param offset first position to write - * @param buffer content to write - * @return EC_SUCCESS: successful
- * EC_FS_READ_ONLY: filesystem is readonly
- * EC_NOT_WRITEABLE: open for writing failed - * EC_POSITION: file position not equals to offset - * EC_WRITE: writing failed - * - */ -ReFileSystem::ErrorCode ReLocalFileSystem::write(const QString& node, - int64_t offset, const QByteArray& buffer) { - ErrorCode rc = EC_SUCCESS; - if (!writeable()) { - m_logger->log(LOG_ERROR, LOC_WRITE_1, "filesystem is readonly"); - rc = EC_FS_READ_ONLY; - } else { - if (offset == 0) { - if (m_writeFile != NULL) - fclose(m_writeFile); - 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()); - rc = EC_NOT_WRITEABLE; - } - } - if (m_writeFile != NULL) { - int64_t position = ReFileUtils::tell(m_writeFile); - if (position != offset) { - rc = EC_POSITION; - m_logger->logv(LOG_ERROR, LOC_WRITE_4, - "wrong file position: %lld/%lld", offset, position); - } else { - int nWritten = fwrite(buffer.constData(), 1, buffer.length(), - 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()); - rc = EC_WRITE; - } - fflush(m_writeFile); - } - } - } - return rc; -} - /** * Constructor. */ @@ -875,3 +813,123 @@ ReOSPermissions&ReOSPermissions::operator =(const ReOSPermissions& source) return *this; } +/** + * Constructor. + * + * @param metaData the meta data of the file + */ +ReLocalLeafFile::ReLocalLeafFile(const ReFileMetaData& metaData, + const QString& fullName, ReLogger* logger) : + ReLeafFile(metaData, fullName, logger), + m_fp(NULL) +{ +} + +/** + * Destructor. + */ +ReLocalLeafFile::~ReLocalLeafFile(){ +} + +/** + * Opens a file for reading or writing. + * + * @param writeable true: open for writing + * @return EC_SUCCESS: success
+ * EC_CANNOT_OPEN: opening failed + */ +ReFileSystem::ErrorCode ReLocalLeafFile::open(bool writeable){ + ReFileSystem::ErrorCode rc = ReFileSystem::EC_SUCCESS; + if ( (m_fp = fopen(m_fullName.toUtf8().constData(), + writeable ?"wb" : "rb")) == NULL){ + rc = ReFileSystem::EC_NOT_EXISTS; + m_logger->logv(LOG_ERROR, LOC_OPEN_1, "cannot open: %s", + m_fullName.toUtf8().constData()); + } + return rc; +} + +/** Frees the resources occupied by open(). + * + * @return EC_SUCCESS: success + */ +ReFileSystem::ErrorCode ReLocalLeafFile::close(){ + ReFileSystem::ErrorCode rc = ReFileSystem::EC_SUCCESS; + if (m_fp != NULL){ + fclose(m_fp); + m_fp = NULL; + } + return rc; +} +/** + * Reads data from the current position into a buffer. + * + * @param size number of bytes to read + * @param buffer OUT: content of the file + * @return EC_SUCCESS: success
+ * EC_INVALID_STATE: file not open + */ +ReFileSystem::ErrorCode ReLocalLeafFile::read(int maxSize, + QByteArray& buffer){ + ReFileSystem::ErrorCode rc = ReFileSystem::EC_SUCCESS; + if (m_fp == NULL){ + rc = ReFileSystem::EC_INVALID_STATE; + } else { + maxSize = min(maxSize, m_meta.m_size - ftell(m_fp)); + buffer.resize(maxSize); + int nRead = 0; + if ( (nRead = fread(buffer.data(), 1, maxSize, m_fp)) != maxSize){ + rc = ReFileSystem::EC_READ; + m_logger->logv(LOG_ERROR, LOC_READ_1, "cannnot read %s (%d): %d/%d", + m_fullName.toUtf8().constData(), errno, nRead, maxSize); + } + } + return rc; +} + +/** + * Writes a buffer to a file at the current position. + * + * @param buffer content to write + * @return EC_SUCCESS or error code + */ +ReFileSystem::ErrorCode ReLocalLeafFile::write(const QByteArray& buffer){ + ReFileSystem::ErrorCode rc = ReFileSystem::EC_SUCCESS; + if (m_fp == NULL){ + rc = ReFileSystem::EC_INVALID_STATE; + } else { + int nWritten = 0; + int nToWrite = buffer.length(); + if ( (nWritten = fwrite(buffer.constData(), 1, nToWrite, m_fp)) != nToWrite){ + rc = ReFileSystem::EC_WRITE; + m_logger->logv(LOG_ERROR, LOC_WRITE_1, "cannnot read %s (%d): %d/%d", + m_fullName.toUtf8().constData(), errno, nWritten, nToWrite); + } + } + return rc; +} + + +/** + * Constructor. + * + * @param metaData metadata of the file + * @param fullName filename with path + * @param logger the logger + */ +ReLeafFile::ReLeafFile(const ReFileMetaData& metaData, const QString& fullName, + ReLogger* logger) : + m_fullName(fullName), + m_logger(logger), + m_meta(metaData) +{ +} + +/** + * Destructor. + */ +ReLeafFile::~ReLeafFile() +{ +} + + diff --git a/os/ReFileSystem.hpp b/os/ReFileSystem.hpp index 122b113..2f99cb0 100644 --- a/os/ReFileSystem.hpp +++ b/os/ReFileSystem.hpp @@ -46,6 +46,13 @@ public: }; typedef QList ReFileMetaDataList; +class ReLeafFile; +/** + * Base class of file systems. + * + * A file system is a hierarchical set of directories with exact one root + * (dirctory). Each directory can contain files and directories. + */ class ReFileSystem { public: enum ListOptions { @@ -73,21 +80,42 @@ public: EC_MARKER, EC_DIR_ALREADY_EXISTS, EC_REMOTE_MKDIR, + EC_CANNOT_OPEN, + EC_INVALID_STATE, + EC_ALREADY_EXISTS, }; public: ReFileSystem(const QString& name, ReLogger* logger); virtual ~ReFileSystem(); public: + /** Creates a new file in the current directory. + * @param node the name of the new file + * @param inDirectoryOnly false: the file is made physically
+ * otherwise: the file exists only in the metadata + * of the directory + * @param metadata OUT: NULL or the metadata of the new file + * @return EC_SUCCESS or the error code + */ + virtual ErrorCode createFile(const QString& node, bool inDirectoryOnly, + ReFileMetaData* metadata = NULL) = 0; + /** + * Returns a filesystem dependent instance of a file. + * + * The file must exist in the current directory. + * The caller must free the instance. + * + * @param meta the metadata of the file + * @return NULL: no file found
+ * otherwise: the file + */ + virtual ReLeafFile* buildFile(const ReFileMetaData& meta) = 0; /** Returns the canonical form of a given path. * @param path path to convert * @return all nodes of the parts which are links are replaced by its * link targets */ virtual QString canonicalPathOf(const QString& path) = 0; - /** Frees resources like open files. - */ - virtual void close() = 0; /** Returns the name of the current directory. * @return the name of the current directory */ @@ -113,15 +141,6 @@ public: * @return EC_SUCCESS or error code */ virtual ErrorCode makeDir(const QString& node) = 0; - /** Reads a part of a file into a buffer. - * @param source the file to read (inside the current directory) - * @param offset first position to read - * @param size number of bytes to read - * @param buffer OUT: content of the file - * @return EC_SUCCESS or error code - */ - virtual ErrorCode read(const ReFileMetaData& source, int64_t offset, - 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 @@ -143,15 +162,21 @@ public: */ virtual ErrorCode setProperties(const ReFileMetaData& source, ReFileMetaData& target, bool force) = 0; - /** Writes a buffer to a file. - * @param target the file to write (without path, inside the current directory) - * @param offset first position to write - * @param buffer content to write - * @return EC_SUCCESS or error code - */ - virtual ErrorCode write(const QString& target, int64_t offset, - const QByteArray& buffer) = 0; public: + /** Returns a filesystem dependent instance of a file. + * + * The file must exist in the current directory. + * The caller must free the instance. + * + * @param node the filename without path + * @return NULL: no file found
+ * otherwise: the file + */ + ReLeafFile* buildFile(const QString& node) { + ReFileMetaData meta; + return exists(node, &meta) ? buildFile(meta) : NULL; + } + virtual ErrorCode copy(ReFileMetaData& source, ReFileSystem& sourceFS); virtual QString errorMessage(ErrorCode rc); public: @@ -199,6 +224,65 @@ protected: ReOSPermissions m_osPermissions; }; +/** + * An abstract base class for leafs of the tree spanned by a filesystem. + * + * A leaf file could not be a directory. + */ +class ReLeafFile : public ReFileMetaData{ +public: + ReLeafFile(const ReFileMetaData& metaData, const QString& fullName, + ReLogger* logger); + virtual ~ReLeafFile(); +public: + /** Opens a file for reading or writing. + * @param writeable true: open for writing + * @return EC_SUCCESS: success
+ * otherwise: the error code + */ + virtual ReFileSystem::ErrorCode open(bool writeable) = 0; + /** Frees the resources occupied by open(). + * @return EC_SUCCESS: success
+ * otherwise: the error code + */ + virtual ReFileSystem::ErrorCode close() = 0; + /** Reads data from the current position into a buffer. + * @param maxSize number of bytes to read + * @param buffer OUT: content of the file + * @return EC_SUCCESS or error code + */ + virtual ReFileSystem::ErrorCode read(int maxSize, QByteArray& buffer) = 0; + /** Writes a buffer to a file at the current position. + * @param buffer content to write + * @return EC_SUCCESS or error code + */ + virtual ReFileSystem::ErrorCode write(const QByteArray& buffer) = 0; +protected: + QString m_fullName; + ReLogger* m_logger; + ReFileMetaData m_meta; +}; + + +/** + * An abstract base class for leafs of the tree spanned by a filesystem. + * + * A leaf file could not be a directory. + */ +class ReLocalLeafFile : public ReLeafFile{ +public: + ReLocalLeafFile(const ReFileMetaData& metaData, const QString& fullName, + ReLogger* logger); + virtual ~ReLocalLeafFile(); +public: + virtual ReFileSystem::ErrorCode open(bool writeable); + virtual ReFileSystem::ErrorCode close(); + virtual ReFileSystem::ErrorCode read(int maxSize, QByteArray& buffer); + virtual ReFileSystem::ErrorCode write(const QByteArray& buffer); +protected: + FILE* m_fp; +}; + class ReLocalFileSystem: public ReFileSystem { public: ReLocalFileSystem(const QString& basePath, ReLogger* logger); @@ -208,31 +292,36 @@ public: ErrorCode setDirectory(const QString& path); public: + /** Returns a file instance of the local filesystem. + * @param meta the metadata of the file + * @return NULL: not found
+ * otherwise: the file + */ + virtual ReLeafFile* buildFile(const ReFileMetaData& meta){ + return new ReLocalLeafFile(meta, fullName(meta.m_node), m_logger); + } /** Returns the canonical form of a given path. * @param path path to convert * @return all nodes of the parts which are links are replaced by its * link targets */ virtual QString canonicalPathOf(const QString& path); - // ReFileSystem interface - virtual void close(); + virtual ErrorCode createFile(const QString& node, bool inDirectoryOnly, + ReFileMetaData* metadata = NULL); virtual bool exists(const QString& node, ReFileMetaData* metaData = NULL) const; virtual int listInfos(const ReIncludeExcludeMatcher& matcher, ReFileMetaDataList& list, ListOptions options); - ErrorCode makeDir(const QString& node); - virtual ErrorCode read(const ReFileMetaData& source, int64_t offset, - int size, QByteArray& buffer); - ErrorCode remove(const ReFileMetaData& node); - ErrorCode setProperties(const ReFileMetaData& source, + virtual ErrorCode makeDir(const QString& node); + virtual ErrorCode remove(const ReFileMetaData& node); + virtual ErrorCode setProperties(const ReFileMetaData& source, ReFileMetaData& target, bool force = false); - virtual ErrorCode write(const QString& target, int64_t offset, - const QByteArray& buffer); protected: QString m_basePath; QDir m_dir; - FILE* m_readFile; - FILE* m_writeFile; + }; + + #endif /* OS_REFILESYSTEM_HPP_ */ -- 2.39.5