]> gitweb.hamatoma.de Git - reqt/commitdiff
dayly work
authorhama <hama@siduction.net>
Sun, 8 Nov 2015 23:25:10 +0000 (00:25 +0100)
committerhama <hama@siduction.net>
Sun, 8 Nov 2015 23:25:10 +0000 (00:25 +0100)
base/ReQStringUtils.cpp
base/ReRandomizer.cpp
base/ReRandomizer.hpp
cunit/allTests.cpp
cunit/cuReRandomizer.cpp
net/renet.hpp
os/ReCryptFileSystem.cpp
os/ReCryptFileSystem.hpp
os/ReFileSystem.cpp

index 4cd1ea2434d2e38322d095c1c2879b67ca4899b4..1f6e4f1053266d062021b479ac4a5e32335150de 100644 (file)
@@ -79,7 +79,7 @@ QString& ReQStringUtils::ensureLastChar(QString& value, QChar lastChar) {
  *                  otherwise: the length of the integer
  */
 int ReQStringUtils::lengthOfUInt64(const ReString& text, int start, int radix,
-       int64_t* pValue) {
+       uint64_t* pValue) {
        int inputLength = text.size();
        int64_t value = 0;
        int ix = start;
index 29e3ab01d2c2f17f43e89c50a97e808cecc61c1c..40db7fef66fc43ddb6136f162e8cbafa6221bfb5 100644 (file)
@@ -169,6 +169,23 @@ const int ReNameScrambler::m_countNodeChars =
        sizeof ReNameScrambler::m_nodeChars;
 
 
+/**
+ * Returns the hash value as hex string.
+ *
+ * Note: After call of this method the hash is reset!
+ *
+ * @return     the hash value as hex string, stored in "little endian" byte order
+ */
+QByteArray ReDigest::hexDigest()
+{
+       QByteArray rc;
+       QByteArray hash = digest();
+       for (int ix = 0; ix < hash.length(); ix++){
+               rc.append(ReStringUtils::toNumber(hash.at(ix) & 0xff, "%02x"));
+       }
+       return rc;
+}
+
 /**
  * Contructor.
  *
@@ -180,33 +197,40 @@ ReHmHash64::ReHmHash64(int64_t factor, int64_t increment) :
        m_increment(increment),
        m_hash(0),
        m_sumLength(0),
-       m_closed(false),
-       m_littleEndian(true)
+       m_rest()
 {
-       int src = 1;
-       int trg = 0;
-       memcpy(&trg, &src, 1);
-       m_littleEndian = trg != 0;
 }
 
 /**
  * Return the hash value as 64 bit integer.
  *
+ * Note: After call of this method the hash is reset!
+ *
  * @return the hash value as 64 bit integer
  */
 int64_t ReHmHash64::digestAsInt()
 {
-       if (! m_closed){
-               m_closed = true;
-               m_hash ^= (m_sumLength ^ 0x2011195811081965L) * m_factor
-                               + (m_increment >> m_sumLength % 29);
+#      define CalcNextHash(data) m_hash ^= (data ^ 0x2004199111121989L) \
+       * m_factor + (m_increment >> (data % 23))
+       // ; printf("%016lx: -> %016lx\n", data, m_hash)
+
+       int64_t rc;
+       if (m_rest.length() > 0){
+               rc = 0;
+               memcpy(&rc, m_rest.constData(), m_rest.length());
+               CalcNextHash(rc);
        }
-       return m_hash;
+       CalcNextHash(m_sumLength);
+       rc = m_hash;
+       reset();
+       return rc;
 }
 
 /**
  * Returns the hash value as byte array.
  *
+ * Note: After call of this method the hash is reset!
+ *
  * @return     the hash value as byte array, stored in "little endian" byte order
  */
 QByteArray ReHmHash64::digest()
@@ -214,26 +238,7 @@ QByteArray ReHmHash64::digest()
        QByteArray rc;
        rc.resize(sizeof m_hash);
        int64_t value = digestAsInt();
-       if (m_littleEndian){
-               * (int64_t*) rc.data() = value;
-       } else {
-               memcpy(rc.data(), &value, sizeof m_hash);
-       }
-       return rc;
-}
-
-/**
- * Returns the hash value as hex string.
- * @return     the hash value as hex string, stored in "big endian" byte order
- */
-QByteArray ReHmHash64::hexDigest()
-{
-       QByteArray rc;
-       int size = sizeof m_hash * 2;
-       rc.reserve(size);
-       rc = QByteArray::number((qlonglong) digestAsInt(), 16);
-       if (rc.length() != size)
-               rc.insert(0, QByteArray("0000000000000000").mid(0, size - rc.length()));
+       memcpy(rc.data(), &value, sizeof m_hash);
        return rc;
 }
 
@@ -244,17 +249,7 @@ QByteArray ReHmHash64::hexDigest()
  */
 void ReHmHash64::reset(){
        m_hash = m_sumLength = 0;
-       m_closed = false;
-}
-
-/**
- * Sets the flag "handle as little endian".
- *
- * @param littleEndian <code>true</code>: the byte order is "little endian"
- */
-void ReHmHash64::setLittleEndian(bool littleEndian)
-{
-       m_littleEndian = littleEndian;
+       m_rest.clear();
 }
 
 /**
@@ -264,45 +259,34 @@ void ReHmHash64::setLittleEndian(bool littleEndian)
  * @param source       the data block which will be added to the hash
  * @param length       the length of the data (in bytes)
  */
-void ReHmHash64::update(void* source, size_t length)
+void ReHmHash64::update(const void* source, size_t length)
 {
-#define CalcNextHash(data) m_hash ^= (data ^ 0x2004199111121989L) \
-       * m_factor + (m_increment >> (data % 23))
+       const uint8_t* src = reinterpret_cast<const uint8_t*>(source);
        int64_t data;
-       if (m_sumLength % sizeof m_hash != 0)
-               ReLogger::logv(LOG_ERROR, LOC_UPDATE_1,
-                                          "ReHmHash64::update() non last block called with wrong length: %d",
-                                          m_sumLength);
        m_sumLength += length;
-       if (m_littleEndian){
-               const int64_t* src = reinterpret_cast<const int64_t*>(source);
-               for (int ix = length / sizeof m_hash - 1; ix >= 0; ix--){
-                       data = *src++;
-                       CalcNextHash(data);
-               }
-               int rest = length % sizeof m_hash;
-               if (rest > 0){
-                       data = 0;
-                       memcpy(&data, src, rest);
-                       data <<= sizeof m_hash - rest;
-                       CalcNextHash(data);
-               }
-       } else {
-               const int8_t* src = reinterpret_cast<const int8_t*>(source);
-               for (int ix = length / sizeof m_hash - 1; ix >= 0; ix--){
-                       data = 0;
-                       for (int ix2 = 0; ix2 < 8; ix2++)
-                               data |= (*src++ << ix2 * 8);
-                       CalcNextHash(data);
-               }
-               int rest = length % sizeof m_hash;
-               if (rest > 0){
-                       data = 0;
-                       memcpy(&data, src, rest);
-                       data <<= sizeof m_hash - rest;
+       if (m_rest.length() > 0){
+               size_t needed = sizeof m_hash - m_rest.length();
+               if (needed > length){
+                       m_rest.append(reinterpret_cast<const char*>(src), length);
+                       length = 0;
+               } else {
+                       m_rest.append(reinterpret_cast<const char*>(src), needed);
+                       length -= needed;
+                       src += needed;
+                       memcpy(&data, m_rest.constData(), sizeof data);
                        CalcNextHash(data);
+                       m_rest.clear();
                }
        }
+       for (int ix = length / sizeof m_hash - 1; ix >= 0; ix--){
+               memcpy(&data, src, sizeof data);
+               src += sizeof data;
+               CalcNextHash(data);
+       }
+       int rest = length % sizeof m_hash;
+       if (rest > 0){
+               m_rest.append(reinterpret_cast<const char*>(src), rest);
+       }
 }
 
 /**
@@ -442,6 +426,30 @@ char ReRandomizer::nextChar() {
        return rc;
 }
 
+/**
+ * @brief Returns binary data with random bytes.
+ *
+ * @param minLength    The minimum length of the result data
+ * @param maxLength    The maximum length of the result data
+ * @param buffer       OUT: The place for the data
+ *
+ * @return                     <code>buffer</code> (for chaining)
+ */
+QByteArray& ReRandomizer::nextData(int minLength, int maxLength,
+       QByteArray &buffer) {
+       int len = nextInt(maxLength, minLength);
+       buffer.resize(len);
+       seed_t data;
+       seed_t* ptr = reinterpret_cast<seed_t*>(buffer.data());
+       for (int ix = len / sizeof data - 1; ix >= 0; ix--)
+               *ptr = nextSeed64();
+       if (len % sizeof data != 0){
+               data = nextSeed64();
+               memcpy(ptr, &data, len % sizeof data);
+       }
+       return buffer;
+}
+
 /**
  * @brief Returns the next random integer.
  *
index 31d13da112a33eb811bfee501b82b4af41a291bd..6cfec37e3831f577bdbe64f1e4cff71f8db5139c 100644 (file)
 #define RANDOMIZER_H_
 
 /**
- * Pure abstract base class for hash generators.
+ * Abstract base class for hash generators.
  */
 class ReDigest {
 public:
        /** Returns the hash value as byte array.
+        * Note: After call of this method the hash is reset!
         * @return      the hash value as byte array, stored in "little endian" byte order
         */
        virtual QByteArray digest() = 0;
-       /** Returns the hash value as hex string.
-        * @return      the hash value as hex string, stored in "little endian" byte order
-        */
-       virtual QByteArray hexDigest() = 0;
        /** Resets the hash.
-        * The state is equal after the constructor.
+        * The state of the instance is the same as after the constructor.
         */
        virtual void reset() = 0;
-       /** Adds the content of a block to the hash.
+       /** Adds the data to the hash.
         * @param source        the data block which will be added to the hash
         * @param length        the length of the data (in bytes)
         */
-       virtual void update(void* source, size_t length) = 0;
+       virtual void update(const void* source, size_t length) = 0;
+public:
+       QByteArray hexDigest();
+       /** Adds the data to the hash.
+        * @param source        the data block which will be added to the hash
+        */
+       inline virtual void updateBlock(const QByteArray& source){
+               update(source.constData(), source.length());
+       }
 };
 
 /**
  * Implements a very simple (and cheap) checksum.
+ *
+ * Features:
+ * <ul><li>If one bit of the content is changed normally many bits of the sum
+ * are changed</li>
+ * <li>If a '\\0' is appended to a sequence of '\\0'' many bits of the sum
+ * are change too</li>
+ * <li>64 bit checksum: low likelihood of collision</li>
+ * <li>Only 6 basic 64 bit operations (*, 2 ^, +, %, >>) per 8 byte content</li>
+ * <li>Works for little/big endian architectures</li>
+ * </ul>
  */
-class ReHmHash64 : ReDigest{
+class ReHmHash64 : public ReDigest{
 public:
        ReHmHash64(int64_t factor = 0x70cf79d585f5a313L,
                           int64_t increment = 0x75c280b9881252dbL);
@@ -47,18 +62,15 @@ public:
        int64_t digestAsInt();
 public:
        virtual QByteArray digest();
-       virtual QByteArray hexDigest();
        virtual void reset();
-       virtual void setLittleEndian(bool littleEndian);
-       virtual void update(void* source, size_t length);
+       virtual void update(const void* source, size_t length);
 
 private:
        int64_t m_factor;
        int64_t m_increment;
        int64_t m_hash;
        int64_t m_sumLength;
-       bool m_closed;
-       bool m_littleEndian;
+       QByteArray m_rest;
 };
 
 /**
@@ -78,6 +90,7 @@ public:
        const QByteArray& name() const;
        seed_t nearTrueRandom();
        char nextChar();
+       QByteArray& nextData(int minLength, int maxLength, QByteArray& buffer);
        int nextInt(int maxValue = INT_MAX, int minValue = 0);
        int64_t nextInt64(int64_t maxValue = LLONG_MAX, int64_t minValue = 0);
        const char* nextString(int minLength, int maxLength, QByteArray& buffer);
index 499b20b89c17c92399e5da3a5f7759c66ee7b034..192e6a26c840925c3a22ade95952ccd6014289d6 100644 (file)
@@ -41,8 +41,8 @@ static void testBase() {
        void testReWriter();
        void testReFile();
        void testReMatcher();
-       testReFileUtils();
        testReRandomizer();
+       testReFileUtils();
        testReMatcher();
        testReQStringUtil();
        testReFile();
index 2504851acd3bc85e8423406c1477a7b66448d00b..17ccd8d39bf407bcbd4ab43b5974371b17b70d22 100644 (file)
@@ -349,15 +349,27 @@ public:
                hash.update((void*) "12345678abcdefghABC", 8+8+3);
                int64_t value = hash.digestAsInt();
                hash.reset();
-               hash.update((void*) "12345678", 8);
-               hash.update((void*) "abcdefgh", 8);
+               hash.update((void*) "1234567", 7);
+               hash.update((void*) "8abcdefgh", 9);
                hash.update((void*) "ABC", 3);
                checkEqu(value, hash.digestAsInt());
 
+               ReKISSRandomizer random;
+               for (int ii = 0; ii < 1000; ii++){
+                       QByteArray string;
+                       random.nextString(1, 64, string);
+                       testOneHash(string, random);
+               }
+               for (int ii = 0; ii < 1000; ii++){
+                       QByteArray data;
+                       random.nextData(1, 64, data);
+                       testOneHash(data, random);
+               }
                printHash("a");
                printHash("b");
                printHash("aa");
                printHash("ab");
+               printHash("ba");
                printHash("aaa");
                printHash("aab");
                printHash("aaaa");
@@ -375,16 +387,42 @@ public:
                        printBinary(ix);
                log("ready");
        }
+       void testOneHash(QByteArray source, ReRandomizer& random){
+               ReHmHash64 hash;
+               hash.update(source.constData(), source.length());
+               int64_t value = hash.digestAsInt();
+
+               while (source.length() > 8){
+                       int count = random.nextInt(1, source.length() - 1);
+                       hash.updateBlock(source.mid(0, count));
+                       source.remove(0, count);
+               }
+               hash.updateBlock(source);
+               checkEqu(value, hash.digestAsInt());
+       }
+
+       void hashPerformance(){
+               ReHmHash64 hash;
+               QByteArray data;
+               data.fill('x', 1024*1024);
+               clock_t start = clock();
+               int count = 100;
+               for (int ix = 0; ix < 100; ix++){
+                       hash.update((void*) data.constData(), data.length());
+               }
+               double duration = double (clock() - start) / CLOCKS_PER_SEC;
+               printf("ReHmHash64: %.3f sec %.3f MByte/sec\n", duration,
+                          count / duration);
+       }
+
        void special(){
-               ReKISSRandomizer rand;
-               rand.dump();
-               rand.nextSeed64();
-               rand.dump();
                log("ready");
        }
 
        virtual void run(void) {
+               special();
                testReHmHash64();
+               hashPerformance();
                testNextString();
                testRealRandom();
                testShuffle();
index 71bbb0d179f3a6e1a29ce49ccf34bb5b3f4e1c6e..489f3f9a09a1cdc46e7d5dc5b433e83b5b58f278 100644 (file)
@@ -21,7 +21,7 @@
 
 #include "net/ReTCPPeer.hpp"
 #include "net/ReTCPServer.hpp"
-#include "net/ReTCPClient.hpp"
+#include "net/ReTcpClient.hpp"
 #include "net/ReNetConfig.hpp"
 
 #endif // RPLNET_HPP
index a4f93ec9bc83e51c7036dc0dc027581b3e56cb24..8b4aa2f95438c46581f21d84cdb28b0793a87310 100644 (file)
  * checksum (from offset 16) (8 byte, encrypted with resetted random)
  * marker (2 byte, encrypted with resetted random)
  * flags (2 byte) see ReFileHeaderOptions
- * reserved (4 byte)
+ * dynamic filelength (4 byte)
  * encrypted file content
  * checksum of the original file content
  * </pre>
- * Checksum: sum_n ^= content_n * FAC + INC,
- * operands 8 byte signed integer, little endian
- * missing bytes (to 8 byte boundary) are padded with 0
- * FAC=0x7b644ac5d1187d25, INC=0x6b85115d6064365b
+ * <b>Calculation of the  checksum:</b><br>
+ * Algorithm: see <code>ReHmHash64</code>
+ * factor=0x7b644ac5d1187d25, increment=0x6b85115d6064365b
+ *
+ * Checksum of the unencrypted file content: straight forward
+ *
+ * Checksum of the encrypted data:<br>
+ * <ul><li>Reset hash</li>
+ * <li>Encrypt data and add it to the hash</li>
+ * <li>Encrypt the checksum of the unencrypted data and add it to the hash</li<
+ * <li>Store the data length (without checksum) to the header</li<
+ * <li>Add the header from offset 16 to the hash</li>
+ * <li>Add the checksum in the header at offset 8</li>
+ * </ul>
  */
 enum {
        LOC_ADD_ENTRY_1 = LOC_FIRST_OF(LOC_CRYPTFILESYSTEM), // 12301
@@ -36,6 +46,8 @@ enum {
        LOC_WRITE_META_1,               // 12306
        LOC_WRITE_META_2,               // 12307
        LOC_MAKE_DIR_1,                 // 12308
+       LOC_FILE_OPEN_1,                // 12309
+       LOC_FILE_WRITE_1,               // 12310
 };
 
 const int ReCryptFileSystem::NODE_LENGHT = 44;
@@ -53,6 +65,12 @@ const int ReCryptDirectory::META_DIR_HEADER_LENGTH = sizeof(int64_t)
 // space for the struct and the node:
 const int ReCryptDirectory::MAX_ENTRY_SIZE = sizeof(ReCryptDirectory::FileEntry_t)
                + 512;
+const int ReCryptDirectory::FILE_MARKER_LENGTH = 2;
+const int ReCryptDirectory::FILE_FLAGS_LENGTH = 2;
+const int ReCryptDirectory::FILE_LENGTH_LENGTH = 4;
+const int ReCryptDirectory::FILE_HEADER_LENGTH = 2 * sizeof(int64_t)
+               + FILE_MARKER_LENGTH + FILE_FLAGS_LENGTH + FILE_LENGTH_LENGTH;
+const int ReCryptDirectory::FILE_CHECKSUM_LENGTH = sizeof(int64_t);
 
 /**
  * Constructor.
@@ -223,7 +241,9 @@ ReFileSystem::ErrorCode ReCryptFileSystem::setProperties(const ReFileMetaData& s
  */
 ReFileSystem::ErrorCode ReCryptFileSystem::write(const QString& target,
        int64_t offset, const QByteArray& buffer) {
-       return EC_SUCCESS;
+       m_contentRandom.reset();
+       QByteArray m_header;
+       return writeFileBlock(target, offset, buffer);
 }
 
 /**
@@ -251,7 +271,7 @@ ReCryptDirectory::ReCryptDirectory(ReRandomizer& contentRandom,
                                                                   ReCryptFileSystem* parent, ReLogger* logger) :
        ReByteScrambler(contentRandom, logger),
        m_list(),
-       m_parent(parent),
+       m_parentFS(parent),
        m_changed(false),
        m_logger2(logger),
        m_currentNode(),
@@ -328,6 +348,16 @@ int ReCryptDirectory::buildId(const QString& hostedNode) const{
        return id;
 }
 
+/**
+ * Returns the buffer for file data blocks.
+ *
+ * @return     the file buffer
+ */
+QByteArray& ReCryptDirectory::fileBuffer()
+{
+       return m_fileBuffer;
+}
+
 /**
  * Search an file entry by name.
  *
@@ -348,6 +378,26 @@ const ReFileMetaData* ReCryptDirectory::find(const QString& node) const
        return rc;
 }
 
+/**
+ * Returns the logger.
+ *
+ * @return     the logger
+ */
+ReLogger*ReCryptDirectory::logger() const
+{
+       return m_logger2;
+}
+
+/**
+ * Returns the parent filesystem.
+ *
+ * @return the parent filesystem
+ */
+ReCryptFileSystem* ReCryptDirectory::parentFS() const
+{
+       return m_parentFS;
+}
+
 /**
  * Removes an entry given by the name.
  *
@@ -366,7 +416,7 @@ bool ReCryptDirectory::removeEntry(const QString& node)
                //@ToDo:
                //m_list.removeOne(entry2);
                assert(false);
-               ReFileSystem& host = m_parent->host();
+               ReFileSystem& host = m_parentFS->host();
                ReFileMetaData hostedFile;
                QString hostedNode = buildHostedNode(entry->m_id);
                if (host.first(hostedNode, hostedFile))
@@ -385,7 +435,7 @@ bool ReCryptDirectory::readMetaFile()
 {
        bool rc = true;
        m_list.clear();
-       QString fnMetaFile = m_parent->directory() + ReCryptFileSystem::NODE_META_DIR;
+       QString fnMetaFile = m_parentFS->directory() + ReCryptFileSystem::NODE_META_DIR;
        FILE* fp = fopen(fnMetaFile.toUtf8().constData(), "rb");
        m_maxFileId = 0;
        if (fp != NULL){
@@ -454,7 +504,7 @@ bool ReCryptDirectory::writeMetaFile()
                int length = node.length();
                meta2->m_size += length + (length < 256 ? 0 : 1);
        }
-       QString fnMetaFile = m_parent->directory() + ReCryptFileSystem::NODE_META_DIR;
+       QString fnMetaFile = m_parentFS->directory() + ReCryptFileSystem::NODE_META_DIR;
        FILE* fp = fopen(fnMetaFile.toUtf8().constData(), "rb");
        if (fp == NULL){
                m_logger->logv(LOG_ERROR, LOC_WRITE_META_1, "cannot write (%d): %s",
@@ -538,6 +588,25 @@ void ReCryptDirectory::splitBlock(bool isLast, QByteArray& block){
        block.remove(0, srcPtr - block.constData());
        printf("List: %d Rest: %d\n", m_list.length(), block.length());
 }
+
+/**
+ * Returns the block size.
+ * @return     the block size
+ */
+int ReCryptDirectory::blockSize() const
+{
+       return m_blockSize;
+}
+/**
+ * Sets the block size.
+ *
+ * @param blockSize    the new block size
+ */
+void ReCryptDirectory::setBlockSize(int blockSize)
+{
+       m_blockSize = blockSize;
+}
+
 /**
  * Gets the filename of an entry in the hosted filesystem.
  *
@@ -547,7 +616,193 @@ void ReCryptDirectory::splitBlock(bool isLast, QByteArray& block){
 const QString& ReCryptDirectory::hostedFilename(const ReFileMetaData& entry)
 {
        QString node = buildHostedNode(entry.m_id);
-       m_currentNode = ReFileUtils::pathAppend(m_parent->directory(), node);
+       m_currentNode = ReFileUtils::pathAppend(m_parentFS->directory(), node);
        return m_currentNode;
 }
 
+/**
+ * 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
+ */
+ReFileSystem::ErrorCode ReCryptDirectory::writeFileBlock(const QString& target,
+                                               int64_t offset, const QByteArray& buffer)
+{
+       ReFileSystem::ErrorCode rc = ReFileSystem::EC_SUCCESS;
+
+       if (offset == 0){
+               ReFileMetaData metaData;
+               if (! m_parentFS->m_parentFS->exists(target, &metaData)){
+                       QDateTime now = QDateTime::currentDateTime();
+                       metaData.m_node = target;
+                       metaData.m_modified = now;
+                       metaData.m_created = now;
+                       metaData.m_owner = m_parentFS->osPermissions().m_user;
+                       metaData.m_group = m_parentFS->osPermissions().m_group;
+                       metaData.m_mode = m_parentFS->osPermissions().m_fileMode;
+                       metaData.m_size = buffer.length() + ReCryptDirectory::FILE_HEADER_LENGTH
+                                       + ReCryptDirectory::FILE_CHECKSUM_LENGTH;
+                       metaData.m_id = ++m_maxFileId;
+               }
+       }
+       return rc;
+}
+
+/**
+ * Constructor.
+ *
+ * @param meta         the file infos
+ * @param directory    the assoziated directory
+ */
+ReCryptFile::ReCryptFile(const ReFileMetaData& meta, ReCryptDirectory& directory) :
+       m_metaData(meta),
+       m_fullHostedName((directory.parentFS()->host().directory()
+                       + directory.parentFS()->buildHostedNode(meta.m_id)).toUtf8()),
+       m_fileHeader(),
+       m_dataSum(0x7b644ac5d1187d25L, 0x6b85115d6064365bL),
+       m_sumOfEncrypted(0x7b644ac5d1187d25L, 0x6b85115d6064365bL),
+       m_fp(NULL),
+       m_directory(directory),
+       m_dataSize(0)
+{
+}
+
+/**
+ * Destructor.
+ */
+ReCryptFile::~ReCryptFile()
+{
+       close();
+}
+
+/**
+ * Initializes the file for reading/writing.
+ *
+ * @param writeable    <code>true</code>: the file can be written
+ * @return                     EC_SUCCESS: success<br>
+ *                                     x
+ */
+ReFileSystem::ErrorCode ReCryptFile::open(bool writeable)
+{
+       ReFileSystem::ErrorCode rc = ReFileSystem::EC_SUCCESS;
+       close();
+       m_fp = fopen(m_fullHostedName, writeable? "wb" : "rb");
+       if (m_fp == NULL){
+               m_directory.logger()->logv(LOG_ERROR, LOC_FILE_OPEN_1, "cannot open hosted file (%d): %s",
+                                                                       errno, m_fullHostedName.constData());
+               rc = writeable ? ReFileSystem::EC_NOT_WRITEABLE : ReFileSystem::EC_NOT_READABLE;
+       }
+       return rc;
+}
+
+/**
+ * Writes a block to the hosted file.
+ *
+ * @param data data to write
+ * @return             EC_SUCCESS: success
+ */
+ReFileSystem::ErrorCode ReCryptFile::writeBlock(const QByteArray& data){
+       ReFileSystem::ErrorCode rc = ReFileSystem::EC_SUCCESS;
+       if (m_fp != NULL && fwrite(data.constData(), data.length(), 1, m_fp)
+                       != size_t(data.length())){
+               m_directory.logger()->logv(LOG_ERROR, LOC_FILE_WRITE_1,
+                       "cannot write (%d): %s", errno, m_fullHostedName.constData());
+               rc = ReFileSystem::EC_NOT_WRITEABLE;
+               fclose(m_fp);
+               m_fp = NULL;
+       }
+       return rc;
+}
+
+/**
+ * Writes a data block to the file.
+ *
+ * @param data
+ * @return
+ */
+ReFileSystem::ErrorCode ReCryptFile::write(const QByteArray& data)
+{
+       ReFileSystem::ErrorCode rc = ReFileSystem::EC_SUCCESS;
+       m_dataSum.updateBlock(data);
+       QByteArray& target = m_directory.fileBuffer();
+       int blockSize = m_directory.blockSize();
+       if (m_dataSize > 0 && m_dataSize <= blockSize){
+               // write the header...
+               if ( (rc = writeBlock(m_fileHeader)) == ReFileSystem::EC_SUCCESS)
+                       // and the first block...
+                       rc = writeBlock(target);
+               target.clear();
+       }
+       m_dataSize += data.length();
+       if (rc == ReFileSystem::EC_SUCCESS){
+               m_directory.encodeContent(data, target);
+               m_sumOfEncrypted.updateBlock(target);
+       }
+       return rc;
+}
+
+/**
+ * Calculates the "dynamic length".
+ *
+ * The dynamic length is the length if it can be stored in a 32 bit integer.
+ * If the length is greater it will be shifted to right until 32 bit is enough.
+ *
+ * @param length       the 64 bit length
+ * @return                     the dynamic length
+ */
+uint32_t ReCryptFile::dynamicLength(int64_t length) {
+       while (length > 0xFFFFffffL)
+               length >>= 1;
+       return uint64_t(length);
+}
+
+/**
+ * Flush data and free resources.
+ *
+ * @return EC_SUCCESS: success
+ */
+ReFileSystem::ErrorCode ReCryptFile::close()
+{
+       ReFileSystem::ErrorCode rc = ReFileSystem::EC_SUCCESS;
+       if (m_fp != NULL){
+               QByteArray& target = m_directory.fileBuffer();
+               int blockSize = m_directory.blockSize();
+               bool doFlush = m_dataSize > 0 && m_dataSize <= blockSize;
+               m_metaData.m_size = m_dataSize;
+               QByteArray checkSum = m_dataSum.digest();
+
+               // Add the data checksum at the end of the data block:
+               target.append(reinterpret_cast<const char*>(&checkSum), sizeof checkSum);
+               // Update the encrypted checksum:
+               m_sumOfEncrypted.update(&checkSum, sizeof checkSum);
+
+               // Update the protected part of the header info:
+               uint32_t size = dynamicLength(m_dataSize);
+               memcpy(m_fileHeader.data() + sizeof(ReRandomizer::seed_t)
+                          + ReCryptDirectory::FILE_FLAGS_LENGTH, &size, sizeof size);
+
+               // Add the protected part of the header to the encrypted checksum:
+               m_sumOfEncrypted.update(m_fileHeader.constData() + 2 * sizeof(int64_t),
+                                                               m_fileHeader.length() - 2 * sizeof(int64_t));
+               // update the unprotected part of the header:
+               memcpy(m_fileHeader.data() + sizeof(ReRandomizer::seed_t), &checkSum,
+                          sizeof checkSum);
+
+               if (doFlush)
+                       target.insert(0, m_fileHeader);
+               rc = writeBlock(target);
+               target.clear();
+               if (m_fp != NULL && ! doFlush){
+                       fseek(m_fp, 0, SEEK_SET);
+                       rc = writeBlock(m_fileHeader);
+               }
+               if (m_fp != NULL){
+                       fclose(m_fp);
+                       m_fp = NULL;
+               }
+       }
+       return rc;
+}
index d24707601f1e5189d6d081b505250b389c7e2c3b..71a458476a71128082d615224b14d6e14527a83e 100644 (file)
 
 class ReCryptFileSystem;
 
-class ReCryptDirectory : protected ReByteScrambler{
+class ReCryptDirectory;
+/**
+ * Administrates an encrypted file for reading / writing.
+ */
+class ReCryptFile {
+public:
+       ReCryptFile(const ReFileMetaData& metaData, ReCryptDirectory& directory);
+       ~ReCryptFile();
+public:
+       ReFileSystem::ErrorCode open(bool writeable);
+       ReFileSystem::ErrorCode write(const QByteArray& data);
+       ReFileSystem::ErrorCode close();
+public:
+       static uint32_t dynamicLength(int64_t length);
+protected:
+       ReFileSystem::ErrorCode writeBlock(const QByteArray& data);
+private:
+       ReFileMetaData m_metaData;
+       QByteArray m_fullHostedName;
+       QByteArray m_fileHeader;
+       /// checksum of the unencrypted data
+       ReHmHash64 m_dataSum;
+       /// checksum of the encrypted data
+       ReHmHash64 m_sumOfEncrypted;
+       FILE* m_fp;
+       ReCryptDirectory& m_directory;
+       int64_t m_dataSize;
+};
+
+/**
+ * Administrates an encrypted directory.
+ */
+class ReCryptDirectory : public ReByteScrambler{
 public:
        typedef struct {
                int64_t m_size;
@@ -33,17 +65,24 @@ public:
        } MetaInfo_t;
 public:
        ReCryptDirectory(ReRandomizer& contentRandom, ReCryptFileSystem* parent,
-                                        ReLogger* logger);
+                       ReLogger* logger);
        ~ReCryptDirectory();
 public:
        bool addEntry(ReFileMetaData& entry);
+       int blockSize() const;
+       QString buildHostedNode(int id) const;
+       QByteArray& fileBuffer();
        const ReFileMetaData* find(const QString& node) const;
+       ReLogger* logger() const;
+       ReCryptFileSystem* parentFS() const;
        bool removeEntry(const QString& entry);
        bool readMetaFile();
+       void setBlockSize(int blockSize);
+       ReFileSystem::ErrorCode writeFileBlock(const QString& target, int64_t offset,
+                                               const QByteArray& buffer);
        bool writeMetaFile();
 protected:
        int buildId(const QString& hostedNode) const;
-       QString buildHostedNode(int id) const;
        const QString& hostedFilename(const ReFileMetaData& entry);
        void splitBlock(bool isLast, QByteArray& block);
 public:
@@ -51,9 +90,15 @@ public:
        static const int META_INFO_LENGTH;
        static const int META_DIR_HEADER_LENGTH;
        static const int MAX_ENTRY_SIZE;
+       static const int FILE_MARKER_LENGTH;
+       static const int FILE_FLAGS_LENGTH;
+       static const int FILE_LENGTH_LENGTH;
+       static const int FILE_HEADER_LENGTH;
+       static const int FILE_CHECKSUM_LENGTH;
+
 protected:
        ReFileMetaDataList m_list;
-       ReCryptFileSystem* m_parent;
+       ReCryptFileSystem* m_parentFS;
        bool m_changed;
        // to avoid ambigousity:
        ReLogger* m_logger2;
@@ -74,7 +119,7 @@ protected:
  * will be encrypted. In the other direction the file content will be decrypted.
  */
 class ReCryptFileSystem: public ReFileSystem,
-               protected ReCryptDirectory
+               public ReCryptDirectory
 {
 public:
        static const int NODE_LENGHT;
index 7fc22eef3cd89eb999dfa628b405009468862aae..9e8734915fdfc558defdaa7e83ccc1e1197e56cf 100644 (file)
@@ -84,6 +84,7 @@ ReFileSystem* ReFileSystem::buildFromUrl(const QString& url)
 #error "missing evaluating drive"
 #endif
        }
+       return rc;
 }
 
 /**
@@ -433,7 +434,7 @@ int ReLocalFileSystem::listInfos(const ReIncludeExcludeMatcher& matcher,
                        full.append(node.toUtf8());
                        if (stat(full.constData(), &info) == 0) {
                                bool isDir = S_ISDIR(info.st_mode);
-                               if (isDir && ! withDirs || ! isDir && ! withFiles)
+                               if ((isDir && ! withDirs) || (! isDir && ! withFiles))
                                        continue;
                                if (! earlyMatching){
                                        if ( (! isDir || matchDirs) && ! matcher.matches(node))
@@ -754,10 +755,11 @@ ReFileMetaData::ReFileMetaData() :
                m_node(),
                m_modified(),
                m_created(),
+               m_size(-1),
                m_owner(-1),
                m_group(-1),
-               m_mode(-1),
-               m_size(-1) {
+               m_mode(-1)
+{
 
 }
 
@@ -870,5 +872,6 @@ ReOSPermissions&ReOSPermissions::operator =(const ReOSPermissions& source)
        m_group = source.m_group;
        m_fileMode = source.m_fileMode;
        m_dirMode = source.m_dirMode;
+       return *this;
 }