/***************************************************************************** * Author: Valient Gough * ***************************************************************************** * Copyright (c) 2012 Valient Gough * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "fs/testing.h" #include #include #include #include "cipher/CipherV1.h" #include "cipher/MemoryPool.h" #include "fs/FSConfig.h" #include "fs/fsconfig.pb.h" #include "fs/FileUtils.h" #include "fs/MACFileIO.h" #include "fs/MemFileIO.h" using std::list; using std::string; namespace encfs { FSConfigPtr makeConfig(const shared_ptr& cipher, int blockSize) { FSConfigPtr cfg = FSConfigPtr(new FSConfig); cfg->cipher = cipher; cfg->key = cipher->newRandomKey(); cfg->cipher->setKey(cfg->key); cfg->config.reset(new EncfsConfig); cfg->config->set_block_size(blockSize); cfg->opts.reset(new EncFS_Opts); return cfg; } void runWithCipher(const string& cipherName, int blockSize, void (*func)(FSConfigPtr& config)) { shared_ptr cipher = CipherV1::New(cipherName); ASSERT_TRUE(cipher.get() != NULL); FSConfigPtr cfg = makeConfig(cipher, blockSize); ASSERT_NO_FATAL_FAILURE(func(cfg)); } void runWithAllCiphers(void (*func)(FSConfigPtr& config)) { list algorithms = CipherV1::GetAlgorithmList(); list::const_iterator it; for (it = algorithms.begin(); it != algorithms.end(); ++it) { int blockSize = it->blockSize.closest(512); int keyLength = it->keyLength.closest(128); SCOPED_TRACE(testing::Message() << "Testng with cipher " << it->name << ", blocksize " << blockSize << ", keyLength " << keyLength); shared_ptr cipher = CipherV1::New(it->iface, keyLength); ASSERT_TRUE(cipher.get() != NULL); FSConfigPtr cfg = makeConfig(cipher, blockSize); ASSERT_NO_FATAL_FAILURE(func(cfg)); } } void truncate(FileIO* a, FileIO* b, int len) { SCOPED_TRACE(testing::Message() << "Truncate from " << a->getSize() << " to len " << len); a->truncate(len); ASSERT_EQ(len, a->getSize()); b->truncate(len); ASSERT_EQ(len, b->getSize()); compare(a, b, 0, len); } void writeRandom(FSConfigPtr& cfg, FileIO* a, FileIO* b, int offset, int len) { SCOPED_TRACE(testing::Message() << "Write random " << offset << ", " << len); if (a->getSize() < offset + len) { a->truncate(offset + len); } if (b->getSize() < offset + len) { b->truncate(offset + len); } unsigned char *buf = new unsigned char[len]; ASSERT_TRUE(cfg->cipher->pseudoRandomize(buf, len)); IORequest req; req.data = new unsigned char[len]; req.dataLen = len; memcpy(req.data, buf, len); req.offset = offset; ASSERT_TRUE(a->write(req)); // Check that write succeeded. req.offset = offset; req.dataLen = len; ASSERT_EQ(len, a->read(req)); ASSERT_TRUE(memcmp(req.data, buf, len) == 0); memcpy(req.data, buf, len); req.offset = offset; req.dataLen = len; ASSERT_TRUE(b->write(req)); // Check that write succeeded. req.offset = offset; req.dataLen = len; ASSERT_EQ(len, b->read(req)); ASSERT_TRUE(memcmp(req.data, buf, len) == 0); compare(a, b, offset, len); delete[] buf; delete[] req.data; } void compare(FileIO* a, FileIO* b, int offset, int len) { SCOPED_TRACE(testing::Message() << "compare " << offset << ", " << len << " from file length " << a->getSize()); unsigned char *buf1 = new unsigned char[len]; unsigned char *buf2 = new unsigned char[len]; memset(buf1, 0, len); memset(buf2, 0, len); IORequest req; req.offset = offset; req.data = buf1; req.dataLen = len; ssize_t size1 = a->read(req); req.offset = offset; req.data = buf2; req.dataLen = len; ssize_t size2 = b->read(req); ASSERT_EQ(size1, size2); for(int i = 0; i < len; i++) { bool match = (buf1[i] == buf2[i]); ASSERT_TRUE(match) << "mismatched data at offset " << i << " of " << len << ", got " << int(buf1[i]) << " and " << int(buf2[i]); if(!match) { break; } } delete[] buf1; delete[] buf2; } void comparisonTest(FSConfigPtr& cfg, FileIO* a, FileIO* b) { const int size = 2*1024; writeRandom(cfg, a, b, 0, size); if (testing::Test::HasFatalFailure()) return; for (int i = 0; i < 10000; i++) { SCOPED_TRACE(testing::Message() << "Test Loop " << i); int len = 128 + random() % 512; int offset = (len == a->getSize()) ? 0 : random() % (a->getSize() - len); writeRandom(cfg, a, b, offset, len); if (testing::Test::HasFatalFailure()) return; ASSERT_EQ(a->getSize(), b->getSize()); } SCOPED_TRACE("Final Compare"); compare(a, b, 0, a->getSize()); } int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } } // namespace encfs