mirror of
https://github.com/vgough/encfs.git
synced 2024-11-21 23:43:26 +01:00
rewrite mempool using thread-local storage, update cmake feature checks
This commit is contained in:
parent
9e55fd35bd
commit
3e15eadec9
@ -86,6 +86,7 @@ find_program (POD2MAN pod2man)
|
|||||||
include (CheckIncludeFileCXX)
|
include (CheckIncludeFileCXX)
|
||||||
check_include_file_cxx (attr/xattr.h HAVE_ATTR_XATTR_H)
|
check_include_file_cxx (attr/xattr.h HAVE_ATTR_XATTR_H)
|
||||||
check_include_file_cxx (sys/xattr.h HAVE_SYS_XATTR_H)
|
check_include_file_cxx (sys/xattr.h HAVE_SYS_XATTR_H)
|
||||||
|
check_include_file_cxx (valgrind/memcheck.h HAVE_VALGRIND_MEMCHECK_H)
|
||||||
|
|
||||||
# Check if xattr functions take extra arguments, as they do on OSX.
|
# Check if xattr functions take extra arguments, as they do on OSX.
|
||||||
include (CheckCXXSourceCompiles)
|
include (CheckCXXSourceCompiles)
|
||||||
@ -98,6 +99,7 @@ check_cxx_source_compiles ("#include <sys/types.h>
|
|||||||
include (CheckFuncs)
|
include (CheckFuncs)
|
||||||
check_function_exists_glibc (lchmod HAVE_LCHMOD)
|
check_function_exists_glibc (lchmod HAVE_LCHMOD)
|
||||||
check_function_exists_glibc (utimensat HAVE_UTIMENSAT)
|
check_function_exists_glibc (utimensat HAVE_UTIMENSAT)
|
||||||
|
check_function_exists_glibc (fdatasync HAVE_FDATASYNC)
|
||||||
|
|
||||||
set (CMAKE_THREAD_PREFER_PTHREAD)
|
set (CMAKE_THREAD_PREFER_PTHREAD)
|
||||||
find_package (Threads REQUIRED)
|
find_package (Threads REQUIRED)
|
||||||
|
@ -2,10 +2,14 @@
|
|||||||
|
|
||||||
#cmakedefine HAVE_ATTR_XATTR_H
|
#cmakedefine HAVE_ATTR_XATTR_H
|
||||||
#cmakedefine HAVE_SYS_XATTR_H
|
#cmakedefine HAVE_SYS_XATTR_H
|
||||||
|
#cmakedefine HAVE_VALGRIND_MEMCHECK_H
|
||||||
|
|
||||||
#cmakedefine XATTR_ADD_OPT
|
#cmakedefine XATTR_ADD_OPT
|
||||||
#cmakedefine XATTR_LLIST
|
#cmakedefine XATTR_LLIST
|
||||||
|
|
||||||
#cmakedefine HAVE_LCHMOD
|
#cmakedefine HAVE_LCHMOD
|
||||||
|
#cmakedefine HAVE_UTIMENSAT
|
||||||
|
#cmakedefine HAVE_FDATASYNC
|
||||||
|
|
||||||
/* TODO: add other thread library support. */
|
/* TODO: add other thread library support. */
|
||||||
#cmakedefine CMAKE_USE_PTHREADS_INIT
|
#cmakedefine CMAKE_USE_PTHREADS_INIT
|
||||||
|
@ -133,11 +133,12 @@ ssize_t BlockFileIO::read(const IORequest &req) const {
|
|||||||
|
|
||||||
// if the request is larger then a block, then request each block
|
// if the request is larger then a block, then request each block
|
||||||
// individually
|
// individually
|
||||||
MemBlock mb; // in case we need to allocate a temporary block..
|
MemBlock mb{}; // in case we need to allocate a temporary block..
|
||||||
IORequest blockReq; // for requests we may need to make
|
IORequest blockReq; // for requests we may need to make
|
||||||
blockReq.dataLen = _blockSize;
|
blockReq.dataLen = _blockSize;
|
||||||
blockReq.data = nullptr;
|
blockReq.data = nullptr;
|
||||||
|
|
||||||
|
rAssert(req.data != nullptr);
|
||||||
unsigned char *out = req.data;
|
unsigned char *out = req.data;
|
||||||
while (size != 0u) {
|
while (size != 0u) {
|
||||||
blockReq.offset = blockNum * _blockSize;
|
blockReq.offset = blockNum * _blockSize;
|
||||||
@ -147,10 +148,8 @@ ssize_t BlockFileIO::read(const IORequest &req) const {
|
|||||||
if (partialOffset == 0 && size >= (size_t)_blockSize) {
|
if (partialOffset == 0 && size >= (size_t)_blockSize) {
|
||||||
blockReq.data = out;
|
blockReq.data = out;
|
||||||
} else {
|
} else {
|
||||||
if (mb.data == nullptr) {
|
mb.allocate(_blockSize);
|
||||||
mb = MemoryPool::allocate(_blockSize);
|
blockReq.data = mb.get();
|
||||||
}
|
|
||||||
blockReq.data = mb.data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t readSize = cacheReadOneBlock(blockReq);
|
ssize_t readSize = cacheReadOneBlock(blockReq);
|
||||||
@ -163,6 +162,7 @@ ssize_t BlockFileIO::read(const IORequest &req) const {
|
|||||||
|
|
||||||
// if we read to a temporary buffer, then move the data
|
// if we read to a temporary buffer, then move the data
|
||||||
if (blockReq.data != out) {
|
if (blockReq.data != out) {
|
||||||
|
rAssert(blockReq.data != nullptr);
|
||||||
memcpy(out, blockReq.data + partialOffset, cpySize);
|
memcpy(out, blockReq.data + partialOffset, cpySize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,10 +177,6 @@ ssize_t BlockFileIO::read(const IORequest &req) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mb.data != nullptr) {
|
|
||||||
MemoryPool::release(mb);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,7 +223,7 @@ bool BlockFileIO::write(const IORequest &req) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// have to merge data with existing block(s)..
|
// have to merge data with existing block(s)..
|
||||||
MemBlock mb;
|
MemBlock mb{};
|
||||||
|
|
||||||
IORequest blockReq;
|
IORequest blockReq;
|
||||||
blockReq.data = nullptr;
|
blockReq.data = nullptr;
|
||||||
@ -250,11 +246,9 @@ bool BlockFileIO::write(const IORequest &req) {
|
|||||||
} else {
|
} else {
|
||||||
// need a temporary buffer, since we have to either merge or pad
|
// need a temporary buffer, since we have to either merge or pad
|
||||||
// the data.
|
// the data.
|
||||||
if (mb.data == nullptr) {
|
mb.allocate(_blockSize);
|
||||||
mb = MemoryPool::allocate(_blockSize);
|
blockReq.data = mb.get();
|
||||||
}
|
memset(blockReq.data, 0, _blockSize);
|
||||||
memset(mb.data, 0, _blockSize);
|
|
||||||
blockReq.data = mb.data;
|
|
||||||
|
|
||||||
if (blockNum > lastNonEmptyBlock) {
|
if (blockNum > lastNonEmptyBlock) {
|
||||||
// just pad..
|
// just pad..
|
||||||
@ -286,10 +280,6 @@ bool BlockFileIO::write(const IORequest &req) {
|
|||||||
partialOffset = 0;
|
partialOffset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mb.data != nullptr) {
|
|
||||||
MemoryPool::release(mb);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,22 +291,22 @@ void BlockFileIO::padFile(off_t oldSize, off_t newSize, bool forceWrite) {
|
|||||||
int newBlockSize = newSize % _blockSize;
|
int newBlockSize = newSize % _blockSize;
|
||||||
|
|
||||||
IORequest req;
|
IORequest req;
|
||||||
MemBlock mb;
|
MemBlock mb{};
|
||||||
|
|
||||||
if (oldLastBlock == newLastBlock) {
|
if (oldLastBlock == newLastBlock) {
|
||||||
// when the real write occurs, it will have to read in the existing
|
// when the real write occurs, it will have to read in the existing
|
||||||
// data and pad it anyway, so we won't do it here (unless we're
|
// data and pad it anyway, so we won't do it here (unless we're
|
||||||
// forced).
|
// forced).
|
||||||
if (forceWrite) {
|
if (forceWrite) {
|
||||||
mb = MemoryPool::allocate(_blockSize);
|
mb.allocate(_blockSize);
|
||||||
req.data = mb.data;
|
req.data = mb.get();
|
||||||
|
|
||||||
req.offset = oldLastBlock * _blockSize;
|
req.offset = oldLastBlock * _blockSize;
|
||||||
req.dataLen = oldSize % _blockSize;
|
req.dataLen = oldSize % _blockSize;
|
||||||
int outSize = newSize % _blockSize; // outSize > req.dataLen
|
int outSize = newSize % _blockSize; // outSize > req.dataLen
|
||||||
|
|
||||||
if (outSize != 0) {
|
if (outSize != 0) {
|
||||||
memset(mb.data, 0, outSize);
|
memset(mb.get(), 0, outSize);
|
||||||
cacheReadOneBlock(req);
|
cacheReadOneBlock(req);
|
||||||
req.dataLen = outSize;
|
req.dataLen = outSize;
|
||||||
cacheWriteOneBlock(req);
|
cacheWriteOneBlock(req);
|
||||||
@ -324,8 +314,8 @@ void BlockFileIO::padFile(off_t oldSize, off_t newSize, bool forceWrite) {
|
|||||||
} else
|
} else
|
||||||
VLOG(1) << "optimization: not padding last block";
|
VLOG(1) << "optimization: not padding last block";
|
||||||
} else {
|
} else {
|
||||||
mb = MemoryPool::allocate(_blockSize);
|
mb.allocate(_blockSize);
|
||||||
req.data = mb.data;
|
req.data = mb.get();
|
||||||
|
|
||||||
// 1. extend the first block to full length
|
// 1. extend the first block to full length
|
||||||
// 2. write the middle empty blocks
|
// 2. write the middle empty blocks
|
||||||
@ -337,7 +327,7 @@ void BlockFileIO::padFile(off_t oldSize, off_t newSize, bool forceWrite) {
|
|||||||
// 1. req.dataLen == 0, iff oldSize was already a multiple of blocksize
|
// 1. req.dataLen == 0, iff oldSize was already a multiple of blocksize
|
||||||
if (req.dataLen != 0) {
|
if (req.dataLen != 0) {
|
||||||
VLOG(1) << "padding block " << oldLastBlock;
|
VLOG(1) << "padding block " << oldLastBlock;
|
||||||
memset(mb.data, 0, _blockSize);
|
memset(mb.get(), 0, _blockSize);
|
||||||
cacheReadOneBlock(req);
|
cacheReadOneBlock(req);
|
||||||
req.dataLen = _blockSize; // expand to full block size
|
req.dataLen = _blockSize; // expand to full block size
|
||||||
cacheWriteOneBlock(req);
|
cacheWriteOneBlock(req);
|
||||||
@ -350,7 +340,7 @@ void BlockFileIO::padFile(off_t oldSize, off_t newSize, bool forceWrite) {
|
|||||||
VLOG(1) << "padding block " << oldLastBlock;
|
VLOG(1) << "padding block " << oldLastBlock;
|
||||||
req.offset = oldLastBlock * _blockSize;
|
req.offset = oldLastBlock * _blockSize;
|
||||||
req.dataLen = _blockSize;
|
req.dataLen = _blockSize;
|
||||||
memset(mb.data, 0, req.dataLen);
|
memset(mb.get(), 0, req.dataLen);
|
||||||
cacheWriteOneBlock(req);
|
cacheWriteOneBlock(req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -359,14 +349,10 @@ void BlockFileIO::padFile(off_t oldSize, off_t newSize, bool forceWrite) {
|
|||||||
if (forceWrite && (newBlockSize != 0)) {
|
if (forceWrite && (newBlockSize != 0)) {
|
||||||
req.offset = newLastBlock * _blockSize;
|
req.offset = newLastBlock * _blockSize;
|
||||||
req.dataLen = newBlockSize;
|
req.dataLen = newBlockSize;
|
||||||
memset(mb.data, 0, req.dataLen);
|
memset(mb.get(), 0, req.dataLen);
|
||||||
cacheWriteOneBlock(req);
|
cacheWriteOneBlock(req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mb.data != nullptr) {
|
|
||||||
MemoryPool::release(mb);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int BlockFileIO::truncateBase(off_t size, FileIO *base) {
|
int BlockFileIO::truncateBase(off_t size, FileIO *base) {
|
||||||
@ -393,12 +379,12 @@ int BlockFileIO::truncateBase(off_t size, FileIO *base) {
|
|||||||
// truncated before the truncate. Then write it back out afterwards,
|
// truncated before the truncate. Then write it back out afterwards,
|
||||||
// since the encoding will change..
|
// since the encoding will change..
|
||||||
off_t blockNum = size / _blockSize;
|
off_t blockNum = size / _blockSize;
|
||||||
MemBlock mb = MemoryPool::allocate(_blockSize);
|
MemBlock mb(_blockSize);
|
||||||
|
|
||||||
IORequest req;
|
IORequest req;
|
||||||
req.offset = blockNum * _blockSize;
|
req.offset = blockNum * _blockSize;
|
||||||
req.dataLen = _blockSize;
|
req.dataLen = _blockSize;
|
||||||
req.data = mb.data;
|
req.data = mb.get();
|
||||||
|
|
||||||
ssize_t rdSz = cacheReadOneBlock(req);
|
ssize_t rdSz = cacheReadOneBlock(req);
|
||||||
|
|
||||||
@ -416,8 +402,6 @@ int BlockFileIO::truncateBase(off_t size, FileIO *base) {
|
|||||||
RLOG(WARNING) << "truncate failure: read " << rdSz
|
RLOG(WARNING) << "truncate failure: read " << rdSz
|
||||||
<< " bytes, partial block of " << partialBlock;
|
<< " bytes, partial block of " << partialBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryPool::release(mb);
|
|
||||||
} else {
|
} else {
|
||||||
// truncating on a block bounday. No need to re-encode the last
|
// truncating on a block bounday. No need to re-encode the last
|
||||||
// block..
|
// block..
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "CipherFileIO.h"
|
#include "CipherFileIO.h"
|
||||||
#include "Error.h"
|
#include "Error.h"
|
||||||
#include "FileIO.h"
|
#include "FileIO.h"
|
||||||
@ -258,7 +259,7 @@ int FileNode::sync(bool datasync) {
|
|||||||
int fh = io->open(O_RDONLY);
|
int fh = io->open(O_RDONLY);
|
||||||
if (fh >= 0) {
|
if (fh >= 0) {
|
||||||
int res = -EIO;
|
int res = -EIO;
|
||||||
#ifdef linux
|
#if defined(HAVE_FDATASYNC)
|
||||||
if (datasync) {
|
if (datasync) {
|
||||||
res = fdatasync(fh);
|
res = fdatasync(fh);
|
||||||
} else {
|
} else {
|
||||||
@ -267,7 +268,6 @@ int FileNode::sync(bool datasync) {
|
|||||||
#else
|
#else
|
||||||
(void)datasync;
|
(void)datasync;
|
||||||
// no fdatasync support
|
// no fdatasync support
|
||||||
// TODO: use autoconfig to check for it..
|
|
||||||
res = fsync(fh);
|
res = fsync(fh);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -149,11 +149,11 @@ ssize_t MACFileIO::readOneBlock(const IORequest &req) const {
|
|||||||
|
|
||||||
int bs = blockSize() + headerSize;
|
int bs = blockSize() + headerSize;
|
||||||
|
|
||||||
MemBlock mb = MemoryPool::allocate(bs);
|
MemBlock mb(bs);
|
||||||
|
|
||||||
IORequest tmp;
|
IORequest tmp;
|
||||||
tmp.offset = locWithHeader(req.offset, bs, headerSize);
|
tmp.offset = locWithHeader(req.offset, bs, headerSize);
|
||||||
tmp.data = mb.data;
|
tmp.data = mb.get();
|
||||||
tmp.dataLen = headerSize + req.dataLen;
|
tmp.dataLen = headerSize + req.dataLen;
|
||||||
|
|
||||||
// get the data from the base FileIO layer
|
// get the data from the base FileIO layer
|
||||||
@ -193,7 +193,6 @@ ssize_t MACFileIO::readOneBlock(const IORequest &req) const {
|
|||||||
long blockNum = req.offset / bs;
|
long blockNum = req.offset / bs;
|
||||||
RLOG(WARNING) << "MAC comparison failure in block " << blockNum;
|
RLOG(WARNING) << "MAC comparison failure in block " << blockNum;
|
||||||
if (!warnOnly) {
|
if (!warnOnly) {
|
||||||
MemoryPool::release(mb);
|
|
||||||
throw Error(_("MAC comparison failure, refusing to read"));
|
throw Error(_("MAC comparison failure, refusing to read"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -209,8 +208,6 @@ ssize_t MACFileIO::readOneBlock(const IORequest &req) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryPool::release(mb);
|
|
||||||
|
|
||||||
return readSize;
|
return readSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,11 +217,11 @@ bool MACFileIO::writeOneBlock(const IORequest &req) {
|
|||||||
int bs = blockSize() + headerSize;
|
int bs = blockSize() + headerSize;
|
||||||
|
|
||||||
// we have the unencrypted data, so we need to attach a header to it.
|
// we have the unencrypted data, so we need to attach a header to it.
|
||||||
MemBlock mb = MemoryPool::allocate(bs);
|
MemBlock mb(bs);
|
||||||
|
|
||||||
IORequest newReq;
|
IORequest newReq;
|
||||||
newReq.offset = locWithHeader(req.offset, bs, headerSize);
|
newReq.offset = locWithHeader(req.offset, bs, headerSize);
|
||||||
newReq.data = mb.data;
|
newReq.data = mb.get();
|
||||||
newReq.dataLen = headerSize + req.dataLen;
|
newReq.dataLen = headerSize + req.dataLen;
|
||||||
|
|
||||||
memset(newReq.data, 0, headerSize);
|
memset(newReq.data, 0, headerSize);
|
||||||
@ -247,11 +244,7 @@ bool MACFileIO::writeOneBlock(const IORequest &req) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// now, we can let the next level have it..
|
// now, we can let the next level have it..
|
||||||
bool ok = base->write(newReq);
|
return base->write(newReq);
|
||||||
|
|
||||||
MemoryPool::release(mb);
|
|
||||||
|
|
||||||
return ok;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int MACFileIO::truncate(off_t size) {
|
int MACFileIO::truncate(off_t size) {
|
||||||
|
@ -18,11 +18,11 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "MemoryPool.h"
|
#include "MemoryPool.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <openssl/ossl_typ.h>
|
#include <openssl/ossl_typ.h>
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#ifdef HAVE_VALGRIND_MEMCHECK_H
|
#ifdef HAVE_VALGRIND_MEMCHECK_H
|
||||||
#include <valgrind/memcheck.h>
|
#include <valgrind/memcheck.h>
|
||||||
@ -33,100 +33,109 @@
|
|||||||
|
|
||||||
#include <openssl/buffer.h>
|
#include <openssl/buffer.h>
|
||||||
|
|
||||||
#define BLOCKDATA(BLOCK) (unsigned char *)BLOCK->data->data
|
|
||||||
|
|
||||||
namespace encfs {
|
namespace encfs {
|
||||||
|
|
||||||
|
static thread_local BlockList *gMemPool = nullptr;
|
||||||
|
|
||||||
struct BlockList {
|
struct BlockList {
|
||||||
BlockList *next;
|
BlockList *next;
|
||||||
int size;
|
BUF_MEM *buf;
|
||||||
BUF_MEM *data;
|
|
||||||
|
unsigned char *get();
|
||||||
|
int size();
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
explicit BlockList(int size);
|
||||||
|
~BlockList();
|
||||||
|
|
||||||
|
BlockList(const BlockList &) = delete;
|
||||||
|
BlockList &operator=(const BlockList &) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
static BlockList *allocBlock(int size) {
|
unsigned char *BlockList::get() {
|
||||||
auto *block = new BlockList;
|
return reinterpret_cast<unsigned char *>(buf->data);
|
||||||
block->size = size;
|
|
||||||
block->data = BUF_MEM_new();
|
|
||||||
BUF_MEM_grow(block->data, size);
|
|
||||||
VALGRIND_MAKE_MEM_NOACCESS(block->data->data, block->data->max);
|
|
||||||
|
|
||||||
return block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void freeBlock(BlockList *el) {
|
int BlockList::size() { return buf->max; }
|
||||||
VALGRIND_MAKE_MEM_UNDEFINED(el->data->data, el->data->max);
|
|
||||||
BUF_MEM_free(el->data);
|
|
||||||
|
|
||||||
delete el;
|
void BlockList::clear() {
|
||||||
|
VALGRIND_MAKE_MEM_UNDEFINED(buf->data, buf->max);
|
||||||
|
memset(buf->data, 0, buf->max);
|
||||||
|
VALGRIND_MAKE_MEM_NOACCESS(buf->data, buf->max);
|
||||||
}
|
}
|
||||||
|
|
||||||
static pthread_mutex_t gMPoolMutex = PTHREAD_MUTEX_INITIALIZER;
|
BlockList::BlockList(int sz) {
|
||||||
static BlockList *gMemPool = nullptr;
|
buf = BUF_MEM_new();
|
||||||
|
BUF_MEM_grow(buf, sz);
|
||||||
|
VALGRIND_MAKE_MEM_NOACCESS(buf->data, buf->max);
|
||||||
|
}
|
||||||
|
|
||||||
MemBlock MemoryPool::allocate(int size) {
|
BlockList::~BlockList() {
|
||||||
pthread_mutex_lock(&gMPoolMutex);
|
VALGRIND_MAKE_MEM_UNDEFINED(buf->data, buf->max);
|
||||||
|
BUF_MEM_free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BlockList *allocateBlock(int size) {
|
||||||
|
// check if we already have a large enough block available..
|
||||||
BlockList *parent = nullptr;
|
BlockList *parent = nullptr;
|
||||||
BlockList *block = gMemPool;
|
BlockList *block = gMemPool;
|
||||||
// check if we already have a large enough block available..
|
while (block != nullptr && block->size() < size) {
|
||||||
while (block != nullptr && block->size < size) {
|
|
||||||
parent = block;
|
parent = block;
|
||||||
block = block->next;
|
block = block->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// unlink block from list
|
|
||||||
if (block != nullptr) {
|
|
||||||
if (parent == nullptr) {
|
|
||||||
gMemPool = block->next;
|
|
||||||
} else {
|
|
||||||
parent->next = block->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&gMPoolMutex);
|
|
||||||
|
|
||||||
if (block == nullptr) {
|
if (block == nullptr) {
|
||||||
block = allocBlock(size);
|
// Allocate a new block.
|
||||||
|
return new BlockList(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// unlink block from list
|
||||||
|
if (parent == nullptr) {
|
||||||
|
gMemPool = block->next;
|
||||||
|
} else {
|
||||||
|
parent->next = block->next;
|
||||||
}
|
}
|
||||||
block->next = nullptr;
|
block->next = nullptr;
|
||||||
|
VALGRIND_MAKE_MEM_UNDEFINED(block->get(), size);
|
||||||
MemBlock result;
|
return block;
|
||||||
result.data = BLOCKDATA(block);
|
|
||||||
result.internalData = block;
|
|
||||||
|
|
||||||
VALGRIND_MAKE_MEM_UNDEFINED(result.data, size);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryPool::release(const MemBlock &mb) {
|
MemBlock::MemBlock(int size) : bl(nullptr) { allocate(size); }
|
||||||
pthread_mutex_lock(&gMPoolMutex);
|
|
||||||
|
|
||||||
auto *block = (BlockList *)mb.internalData;
|
MemBlock::~MemBlock() {
|
||||||
|
if (bl == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// just to be sure there's nothing important left in buffers..
|
bl->clear();
|
||||||
VALGRIND_MAKE_MEM_UNDEFINED(block->data->data, block->size);
|
bl->next = gMemPool;
|
||||||
memset(BLOCKDATA(block), 0, block->size);
|
gMemPool = bl;
|
||||||
VALGRIND_MAKE_MEM_NOACCESS(block->data->data, block->data->max);
|
bl = nullptr;
|
||||||
|
data = nullptr;
|
||||||
block->next = gMemPool;
|
|
||||||
gMemPool = block;
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&gMPoolMutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryPool::destroyAll() {
|
void MemBlock::allocate(int size) {
|
||||||
pthread_mutex_lock(&gMPoolMutex);
|
if (bl != nullptr) {
|
||||||
|
if (size <= bl->size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
BlockList *block = gMemPool;
|
// Return existing block.
|
||||||
gMemPool = nullptr;
|
bl->clear();
|
||||||
|
bl->next = gMemPool;
|
||||||
|
gMemPool = bl;
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&gMPoolMutex);
|
bl = allocateBlock(size);
|
||||||
|
data = bl->get();
|
||||||
|
}
|
||||||
|
|
||||||
while (block != nullptr) {
|
void MemBlock::freeAll() {
|
||||||
BlockList *next = block->next;
|
while (gMemPool != nullptr) {
|
||||||
|
BlockList *next = gMemPool->next;
|
||||||
|
|
||||||
freeBlock(block);
|
delete gMemPool;
|
||||||
block = next;
|
gMemPool = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,29 +23,43 @@
|
|||||||
|
|
||||||
namespace encfs {
|
namespace encfs {
|
||||||
|
|
||||||
struct MemBlock {
|
struct BlockList;
|
||||||
|
|
||||||
|
// MemBlock holds a memory block stored in secure memory
|
||||||
|
// (if possible with the crypto backend). Blocks should be
|
||||||
|
// of consistent size, as the allocator is meant for working with
|
||||||
|
// file crypt blocks.
|
||||||
|
//
|
||||||
|
// To get a block, construct a MemBlock and call allocate(), or
|
||||||
|
// use the constructor with size. This either grabs a block from
|
||||||
|
// the thread-local block queue, or else constructs a new block.
|
||||||
|
//
|
||||||
|
// When the MemBlock instance is destroyed, the block is returned
|
||||||
|
// to the list for reuse.
|
||||||
|
class MemBlock {
|
||||||
|
public:
|
||||||
|
MemBlock() =default;
|
||||||
|
explicit MemBlock(int size);
|
||||||
|
~MemBlock();
|
||||||
|
|
||||||
|
bool valid() const;
|
||||||
|
void allocate(int size);
|
||||||
|
|
||||||
|
unsigned char *get() const;
|
||||||
|
|
||||||
|
static void freeAll();
|
||||||
|
|
||||||
|
private:
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
|
BlockList *bl;
|
||||||
void *internalData;
|
|
||||||
|
|
||||||
MemBlock();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline MemBlock::MemBlock() : data(0), internalData(0) {}
|
inline bool MemBlock::valid() const {
|
||||||
|
return bl != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
inline unsigned char *MemBlock::get() const {
|
||||||
Memory Pool for fixed sized objects.
|
return data;
|
||||||
|
|
||||||
Usage:
|
|
||||||
MemBlock mb = MemoryPool::allocate( size );
|
|
||||||
// do things with storage in mb.data
|
|
||||||
unsigned char *buffer = mb.data;
|
|
||||||
MemoryPool::release( mb );
|
|
||||||
*/
|
|
||||||
namespace MemoryPool {
|
|
||||||
MemBlock allocate(int size);
|
|
||||||
void release(const MemBlock &el);
|
|
||||||
void destroyAll();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace encfs
|
} // namespace encfs
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "Error.h"
|
#include "Error.h"
|
||||||
#include "FileIO.h"
|
#include "FileIO.h"
|
||||||
#include "RawFileIO.h"
|
#include "RawFileIO.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@ -257,9 +258,6 @@ int RawFileIO::truncate(off_t size) {
|
|||||||
|
|
||||||
if (fd >= 0 && canWrite) {
|
if (fd >= 0 && canWrite) {
|
||||||
res = ::ftruncate(fd, size);
|
res = ::ftruncate(fd, size);
|
||||||
#if !defined(__FreeBSD__) && !defined(__APPLE__)
|
|
||||||
::fdatasync(fd);
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
res = ::truncate(name.c_str(), size);
|
res = ::truncate(name.c_str(), size);
|
||||||
}
|
}
|
||||||
@ -276,6 +274,12 @@ int RawFileIO::truncate(off_t size) {
|
|||||||
knownSize = true;
|
knownSize = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(HAVE_FDATASYNC)
|
||||||
|
if (fd >= 0 && canWrite) {
|
||||||
|
::fdatasync(fd);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,48 +161,48 @@ int TimedPBKDF2(const char *pass, int passlen, const unsigned char *salt,
|
|||||||
// - Version 3:0 adds a new IV mechanism
|
// - Version 3:0 adds a new IV mechanism
|
||||||
static Interface BlowfishInterface("ssl/blowfish", 3, 0, 2);
|
static Interface BlowfishInterface("ssl/blowfish", 3, 0, 2);
|
||||||
static Interface AESInterface("ssl/aes", 3, 0, 2);
|
static Interface AESInterface("ssl/aes", 3, 0, 2);
|
||||||
static Interface CAMELLIAInterface("ssl/camellia",3, 0, 2);
|
static Interface CAMELLIAInterface("ssl/camellia", 3, 0, 2);
|
||||||
|
|
||||||
#ifndef OPENSSL_NO_CAMELLIA
|
#ifndef OPENSSL_NO_CAMELLIA
|
||||||
|
|
||||||
static Range CAMELLIAKeyRange(128, 256, 64);
|
static Range CAMELLIAKeyRange(128, 256, 64);
|
||||||
static Range CAMELLIABlockRange(64, 4096, 16);
|
static Range CAMELLIABlockRange(64, 4096, 16);
|
||||||
|
|
||||||
static std::shared_ptr<Cipher> NewCAMELLIACipher(const Interface &iface, int keyLen) {
|
static std::shared_ptr<Cipher> NewCAMELLIACipher(const Interface &iface,
|
||||||
if (keyLen <= 0) keyLen = 192;
|
int keyLen) {
|
||||||
|
if (keyLen <= 0) keyLen = 192;
|
||||||
|
|
||||||
keyLen = CAMELLIAKeyRange.closest(keyLen);
|
keyLen = CAMELLIAKeyRange.closest(keyLen);
|
||||||
|
|
||||||
const EVP_CIPHER *blockCipher = 0;
|
const EVP_CIPHER *blockCipher = 0;
|
||||||
const EVP_CIPHER *streamCipher = 0;
|
const EVP_CIPHER *streamCipher = 0;
|
||||||
|
|
||||||
switch (keyLen) {
|
switch (keyLen) {
|
||||||
case 128:
|
case 128:
|
||||||
blockCipher = EVP_camellia_128_cbc();
|
blockCipher = EVP_camellia_128_cbc();
|
||||||
streamCipher = EVP_camellia_128_cfb();
|
streamCipher = EVP_camellia_128_cfb();
|
||||||
break;
|
break;
|
||||||
case 192:
|
case 192:
|
||||||
blockCipher = EVP_camellia_192_cbc();
|
blockCipher = EVP_camellia_192_cbc();
|
||||||
streamCipher = EVP_camellia_192_cfb();
|
streamCipher = EVP_camellia_192_cfb();
|
||||||
break;
|
break;
|
||||||
case 256:
|
case 256:
|
||||||
default:
|
default:
|
||||||
blockCipher = EVP_camellia_256_cbc();
|
blockCipher = EVP_camellia_256_cbc();
|
||||||
streamCipher = EVP_camellia_256_cfb();
|
streamCipher = EVP_camellia_256_cfb();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::shared_ptr<Cipher>(new SSL_Cipher(
|
return std::shared_ptr<Cipher>(new SSL_Cipher(
|
||||||
iface, CAMELLIAInterface, blockCipher, streamCipher, keyLen / 8 ));
|
iface, CAMELLIAInterface, blockCipher, streamCipher, keyLen / 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool CAMELLIA_Cipher_registered =
|
static bool CAMELLIA_Cipher_registered =
|
||||||
Cipher::Register("CAMELLIA","16 byte block cipher", CAMELLIAInterface, CAMELLIAKeyRange,
|
Cipher::Register("CAMELLIA", "16 byte block cipher", CAMELLIAInterface,
|
||||||
CAMELLIABlockRange, NewCAMELLIACipher );
|
CAMELLIAKeyRange, CAMELLIABlockRange, NewCAMELLIACipher);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifndef OPENSSL_NO_BF
|
#ifndef OPENSSL_NO_BF
|
||||||
|
|
||||||
static Range BFKeyRange(128, 256, 32);
|
static Range BFKeyRange(128, 256, 32);
|
||||||
|
@ -724,7 +724,7 @@ int main(int argc, char *argv[]) {
|
|||||||
rootInfo.reset();
|
rootInfo.reset();
|
||||||
ctx->setRoot(std::shared_ptr<DirNode>());
|
ctx->setRoot(std::shared_ptr<DirNode>());
|
||||||
|
|
||||||
MemoryPool::destroyAll();
|
MemBlock::freeAll();
|
||||||
openssl_shutdown(encfsArgs->isThreaded);
|
openssl_shutdown(encfsArgs->isThreaded);
|
||||||
|
|
||||||
return returnCode;
|
return returnCode;
|
||||||
|
@ -54,41 +54,39 @@ const int FSBlockSize = 256;
|
|||||||
static int checkErrorPropogation(const std::shared_ptr<Cipher> &cipher,
|
static int checkErrorPropogation(const std::shared_ptr<Cipher> &cipher,
|
||||||
int size, int byteToChange,
|
int size, int byteToChange,
|
||||||
const CipherKey &key) {
|
const CipherKey &key) {
|
||||||
MemBlock orig = MemoryPool::allocate(size);
|
MemBlock orig(size);
|
||||||
MemBlock data = MemoryPool::allocate(size);
|
MemBlock data(size);
|
||||||
|
|
||||||
for (int i = 0; i < size; ++i) {
|
for (int i = 0; i < size; ++i) {
|
||||||
unsigned char tmp = rand();
|
unsigned char tmp = rand();
|
||||||
orig.data[i] = tmp;
|
orig.get()[i] = tmp;
|
||||||
data.data[i] = tmp;
|
data.get()[i] = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size != FSBlockSize)
|
if (size != FSBlockSize) {
|
||||||
cipher->streamEncode(data.data, size, 0, key);
|
cipher->streamEncode(data.get(), size, 0, key);
|
||||||
else
|
} else {
|
||||||
cipher->blockEncode(data.data, size, 0, key);
|
cipher->blockEncode(data.get(), size, 0, key);
|
||||||
|
}
|
||||||
|
|
||||||
// intoduce an error in the encoded data, so we can check error propogation
|
// intoduce an error in the encoded data, so we can check error propogation
|
||||||
if (byteToChange >= 0 && byteToChange < size) {
|
if (byteToChange >= 0 && byteToChange < size) {
|
||||||
unsigned char previousValue = data.data[byteToChange];
|
unsigned char previousValue = data.get()[byteToChange];
|
||||||
do {
|
do {
|
||||||
data.data[byteToChange] = rand();
|
data.get()[byteToChange] = rand();
|
||||||
} while (data.data[byteToChange] == previousValue);
|
} while (data.get()[byteToChange] == previousValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size != FSBlockSize)
|
if (size != FSBlockSize)
|
||||||
cipher->streamDecode(data.data, size, 0, key);
|
cipher->streamDecode(data.get(), size, 0, key);
|
||||||
else
|
else
|
||||||
cipher->blockDecode(data.data, size, 0, key);
|
cipher->blockDecode(data.get(), size, 0, key);
|
||||||
|
|
||||||
int numByteErrors = 0;
|
int numByteErrors = 0;
|
||||||
for (int i = 0; i < size; ++i) {
|
for (int i = 0; i < size; ++i) {
|
||||||
if (data.data[i] != orig.data[i]) ++numByteErrors;
|
if (data.get()[i] != orig.get()[i]) ++numByteErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryPool::release(data);
|
|
||||||
MemoryPool::release(orig);
|
|
||||||
|
|
||||||
return numByteErrors;
|
return numByteErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,7 +450,7 @@ int main(int argc, char *argv[]) {
|
|||||||
runTests(cipher, true);
|
runTests(cipher, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryPool::destroyAll();
|
MemBlock::freeAll();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user