Hello community,
here is the log from the commit of package cryfs for openSUSE:Factory checked in at 2019-02-08 12:15:47
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/cryfs (Old)
and /work/SRC/openSUSE:Factory/.cryfs.new.28833 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "cryfs"
Fri Feb 8 12:15:47 2019 rev:3 rq:672572 version:0.9.10
Changes:
--------
--- /work/SRC/openSUSE:Factory/cryfs/cryfs.changes 2018-03-07 10:40:07.622684610 +0100
+++ /work/SRC/openSUSE:Factory/.cryfs.new.28833/cryfs.changes 2019-02-08 12:15:48.781415131 +0100
@@ -1,0 +2,8 @@
+Sat Feb 2 14:24:24 UTC 2019 - Klaas Freitag
+
+- Update to upstream version 0.9.10
+ * Fixed occasional deadlock (#64)
+ * Fix for reading empty files out of bounds
+ * Fixed race condition (#224 and #243)
+
+-------------------------------------------------------------------
Old:
----
cryfs-0.9.9.tar.xz
New:
----
cryfs-0.9.10.tar.xz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ cryfs.spec ++++++
--- /var/tmp/diff_new_pack.yPUpMS/_old 2019-02-08 12:15:49.657414803 +0100
+++ /var/tmp/diff_new_pack.yPUpMS/_new 2019-02-08 12:15:49.661414801 +0100
@@ -1,7 +1,7 @@
#
# spec file for package cryfs
#
-# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
# Copyright (c) 2007-2011 Klaas Freitag
#
# All modifications and additions to the file contributed by third parties
@@ -13,14 +13,15 @@
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
-# Please submit bugfixes or comments via http://bugs.opensuse.org/
+# Please submit bugfixes or comments via https://bugs.opensuse.org/
#
+
Name: cryfs
-Version: 0.9.9
+Version: 0.9.10
Release: 0
Summary: CryFS encryption
-License: LGPL-3.0
+License: LGPL-3.0-only
Group: System/Filesystems
Source: %{name}-%{version}.tar.xz
URL: https://github.com/cryfs/cryfs
@@ -41,11 +42,11 @@
%endif
BuildRequires: pkgconfig
-BuildRequires: pkgconfig(libcurl)
BuildRequires: pkgconfig(fuse)
+BuildRequires: pkgconfig(libcurl)
# BuildRequires: pkgconfig(libopenssl)
-BuildRequires: libopenssl-devel
BuildRequires: libcryptopp-devel
+BuildRequires: libopenssl-devel
#=================================
@@ -84,4 +85,5 @@
%{_mandir}/man?/cryfs*
%doc README.md ChangeLog.txt
%license LICENSE
+
%changelog
++++++ cryfs-0.9.9.tar.xz -> cryfs-0.9.10.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/.travis.yml new/.travis.yml
--- old/.travis.yml 2018-02-05 04:16:25.000000000 +0100
+++ new/.travis.yml 2019-01-21 04:39:01.000000000 +0100
@@ -18,6 +18,8 @@
- libcrypto++-dev
- libfuse-dev
install:
+# Workaround homebrew bug, see https://twitter.com/axccl/status/1083393735277363205 and https://github.com/openPMD/openPMD-api/pull/431/files
+- if [ "${TRAVIS_OS_NAME}" == "osx" ]; then travis_wait brew upgrade --cleanup; travis_wait brew upgrade --cleanup; fi
# Use new clang
- if [ "${TRAVIS_OS_NAME}" == "linux" ] && [ "$CXX" = "clang++" ]; then export CXX="clang++-3.7" CC="clang-3.7"; fi
# Detect number of CPU cores
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ChangeLog.txt new/ChangeLog.txt
--- old/ChangeLog.txt 2018-02-05 04:16:25.000000000 +0100
+++ new/ChangeLog.txt 2019-01-21 04:39:01.000000000 +0100
@@ -1,3 +1,10 @@
+Version 0.9.10
+--------------
+Fixed bugs:
+* Fixed occasional deadlock (https://github.com/cryfs/cryfs/issues/64)
+* Fix for reading empty files out of bounds
+* Fixed race condition (https://github.com/cryfs/cryfs/issues/224 and https://github.com/cryfs/cryfs/issues/243)
+
Version 0.9.9
--------------
Improvements:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/src/blobstore/implementations/onblocks/BlobOnBlocks.cpp new/src/blobstore/implementations/onblocks/BlobOnBlocks.cpp
--- old/src/blobstore/implementations/onblocks/BlobOnBlocks.cpp 2018-02-05 04:16:25.000000000 +0100
+++ new/src/blobstore/implementations/onblocks/BlobOnBlocks.cpp 2019-01-21 04:39:01.000000000 +0100
@@ -26,6 +26,11 @@
}
uint64_t BlobOnBlocks::size() const {
+ std::unique_lockstd::mutex lock(_datatree->mutex());
+ return _size();
+}
+
+uint64_t BlobOnBlocks::_size() const {
if (_sizeCache == boost::none) {
_sizeCache = _datatree->numStoredBytes();
}
@@ -33,15 +38,17 @@
}
void BlobOnBlocks::resize(uint64_t numBytes) {
+ std::unique_lockstd::mutex lock(_datatree->mutex());
+
_datatree->resizeNumBytes(numBytes);
_sizeCache = numBytes;
}
-void BlobOnBlocks::traverseLeaves(uint64_t beginByte, uint64_t sizeBytes, function func) const {
+void BlobOnBlocks::_traverseLeaves(uint64_t beginByte, uint64_t sizeBytes, function func) const {
uint64_t endByte = beginByte + sizeBytes;
uint32_t firstLeaf = beginByte / _datatree->maxBytesPerLeaf();
uint32_t endLeaf = utils::ceilDivision(endByte, _datatree->maxBytesPerLeaf());
- bool writingOutside = size() < endByte; // TODO Calling size() is slow because it has to traverse the tree
+ bool writingOutside = _size() < endByte; // TODO Calling size() is slow because it has to traverse the tree
_datatree->traverseLeaves(firstLeaf, endLeaf, [&func, beginByte, endByte, endLeaf, writingOutside](DataLeafNode *leaf, uint32_t leafIndex) {
uint64_t indexOfFirstLeafByte = leafIndex * leaf->maxStoreableBytes();
uint32_t dataBegin = utils::maxZeroSubtraction(beginByte, indexOfFirstLeafByte);
@@ -59,41 +66,70 @@
}
Data BlobOnBlocks::readAll() const {
+ std::unique_lockstd::mutex lock(_datatree->mutex());
+
//TODO Querying size is inefficient. Is this possible without a call to size()?
- uint64_t count = size();
+ uint64_t count = _size();
Data result(count);
_read(result.data(), 0, count);
return result;
}
void BlobOnBlocks::read(void *target, uint64_t offset, uint64_t count) const {
- ASSERT(offset <= size() && offset + count <= size(), "BlobOnBlocks::read() read outside blob. Use BlobOnBlocks::tryRead() if this should be allowed.");
- uint64_t read = tryRead(target, offset, count);
- ASSERT(read == count, "BlobOnBlocks::read() couldn't read all requested bytes. Use BlobOnBlocks::tryRead() if this should be allowed.");
+ std::unique_lockstd::mutex lock(_datatree->mutex());
+
+ if(offset > _size() || offset + count > _size()) {
+ throw std::runtime_error("BlobOnBlocks::read() read outside blob. Use BlobOnBlocks::tryRead() if this should be allowed.");
+ }
+ uint64_t read = _tryRead(target, offset, count);
+ if(read != count) {
+ throw std::runtime_error("BlobOnBlocks::read() couldn't read all requested bytes. Use BlobOnBlocks::tryRead() if this should be allowed.");
+ }
}
uint64_t BlobOnBlocks::tryRead(void *target, uint64_t offset, uint64_t count) const {
+ std::unique_lockstd::mutex lock(_datatree->mutex());
+ return _tryRead(target, offset, count);
+}
+
+uint64_t BlobOnBlocks::_tryRead(void *target, uint64_t offset, uint64_t count) const {
+ if (_size() <= offset) {
+ return 0;
+ }
+
//TODO Quite inefficient to call size() here, because that has to traverse the tree
- uint64_t realCount = std::max(UINT64_C(0), std::min(count, size()-offset));
+ uint64_t realCount = std::max(INT64_C(0), std::min(static_cast(count), static_cast(_size())-static_cast(offset)));
_read(target, offset, realCount);
return realCount;
}
void BlobOnBlocks::_read(void *target, uint64_t offset, uint64_t count) const {
- traverseLeaves(offset, count, [target, offset] (uint64_t indexOfFirstLeafByte, const DataLeafNode *leaf, uint32_t leafDataOffset, uint32_t leafDataSize) {
+ if (count == 0) {
+ return;
+ }
+
+ _traverseLeaves(offset, count, [target, offset] (uint64_t indexOfFirstLeafByte, const DataLeafNode *leaf, uint32_t leafDataOffset, uint32_t leafDataSize) {
//TODO Simplify formula, make it easier to understand
leaf->read((uint8_t*)target + indexOfFirstLeafByte - offset + leafDataOffset, leafDataOffset, leafDataSize);
});
}
void BlobOnBlocks::write(const void *source, uint64_t offset, uint64_t count) {
- traverseLeaves(offset, count, [source, offset] (uint64_t indexOfFirstLeafByte, DataLeafNode *leaf, uint32_t leafDataOffset, uint32_t leafDataSize) {
+ if (count == 0) {
+ return;
+ }
+
+ std::unique_lockstd::mutex lock(_datatree->mutex());
+
+ _traverseLeaves(offset, count, [source, offset] (uint64_t indexOfFirstLeafByte, DataLeafNode *leaf, uint32_t leafDataOffset, uint32_t leafDataSize) {
//TODO Simplify formula, make it easier to understand
leaf->write((uint8_t*)source + indexOfFirstLeafByte - offset + leafDataOffset, leafDataOffset, leafDataSize);
});
}
void BlobOnBlocks::flush() {
+ std::unique_lockstd::mutex lock(_datatree->mutex());
+
_datatree->flush();
}
@@ -102,6 +138,8 @@
}
unique_ref<DataTreeRef> BlobOnBlocks::releaseTree() {
+ std::unique_lockstd::mutex lock(_datatree->mutex());
+
return std::move(_datatree);
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/src/blobstore/implementations/onblocks/BlobOnBlocks.h new/src/blobstore/implementations/onblocks/BlobOnBlocks.h
--- old/src/blobstore/implementations/onblocks/BlobOnBlocks.h 2018-02-05 04:16:25.000000000 +0100
+++ new/src/blobstore/implementations/onblocks/BlobOnBlocks.h 2019-01-21 04:39:01.000000000 +0100
@@ -37,8 +37,11 @@
private:
+ uint64_t _size() const;
+
void _read(void *target, uint64_t offset, uint64_t count) const;
- void traverseLeaves(uint64_t offsetBytes, uint64_t sizeBytes, std::function) const;
+ uint64_t _tryRead(void *target, uint64_t offset, uint64_t size) const;
+ void _traverseLeaves(uint64_t offsetBytes, uint64_t sizeBytes, std::function) const;
cpputils::unique_refparallelaccessdatatreestore::DataTreeRef _datatree;
mutable boost::optional _sizeCache;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/src/blobstore/implementations/onblocks/datatreestore/DataTree.cpp new/src/blobstore/implementations/onblocks/datatreestore/DataTree.cpp
--- old/src/blobstore/implementations/onblocks/datatreestore/DataTree.cpp 2018-02-05 04:16:25.000000000 +0100
+++ new/src/blobstore/implementations/onblocks/datatreestore/DataTree.cpp 2019-01-21 04:39:01.000000000 +0100
@@ -158,6 +158,10 @@
}
void DataTree::traverseLeaves(uint32_t beginIndex, uint32_t endIndex, function func) {
+ if (endIndex <= beginIndex) {
+ return;
+ }
+
//TODO Can we traverse in parallel?
unique_lock lock(_mutex); //TODO Only lock when resizing. Otherwise parallel read/write to a blob is not possible!
ASSERT(beginIndex <= endIndex, "Invalid parameters");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/src/blobstore/implementations/onblocks/datatreestore/DataTree.h new/src/blobstore/implementations/onblocks/datatreestore/DataTree.h
--- old/src/blobstore/implementations/onblocks/datatreestore/DataTree.h 2018-02-05 04:16:25.000000000 +0100
+++ new/src/blobstore/implementations/onblocks/datatreestore/DataTree.h 2019-01-21 04:39:01.000000000 +0100
@@ -38,7 +38,14 @@
void flush() const;
+ // This is a hack to fix a race condition. This is only done in the 0.9 release branch to workaround the issue,
+ // the develop branch and 0.10 release series have a proper fix.
+ std::mutex& mutex() const {
+ return _outerMutex;
+ }
+
private:
+ mutable std::mutex _outerMutex;
mutable boost::shared_mutex _mutex;
datanodestore::DataNodeStore *_nodeStore;
cpputils::unique_refdatanodestore::DataNode _rootNode;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/src/blobstore/implementations/onblocks/parallelaccessdatatreestore/DataTreeRef.h new/src/blobstore/implementations/onblocks/parallelaccessdatatreestore/DataTreeRef.h
--- old/src/blobstore/implementations/onblocks/parallelaccessdatatreestore/DataTreeRef.h 2018-02-05 04:16:25.000000000 +0100
+++ new/src/blobstore/implementations/onblocks/parallelaccessdatatreestore/DataTreeRef.h 2019-01-21 04:39:01.000000000 +0100
@@ -41,6 +41,12 @@
return _baseTree->flush();
}
+ // This is a hack to fix a race condition. This is only done in the 0.9 release branch to workaround the issue,
+ // the develop branch and 0.10 release series have a proper fix.
+ std::mutex& mutex() const {
+ return _baseTree->mutex();
+ }
+
private:
datatreestore::DataTree *_baseTree;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/src/cpp-utils/random/ThreadsafeRandomDataBuffer.h new/src/cpp-utils/random/ThreadsafeRandomDataBuffer.h
--- old/src/cpp-utils/random/ThreadsafeRandomDataBuffer.h 2018-02-05 04:16:25.000000000 +0100
+++ new/src/cpp-utils/random/ThreadsafeRandomDataBuffer.h 2019-01-21 04:39:01.000000000 +0100
@@ -54,7 +54,7 @@
inline size_t ThreadsafeRandomDataBuffer::_get(void *target, size_t numBytes) {
boost::unique_lockboost::mutex lock(_mutex);
- _dataAddedCv.wait(lock, [this, numBytes] {
+ _dataAddedCv.wait(lock, [this] {
return _buffer.size() > 0;
});
size_t gettableBytes = std::min(_buffer.size(), numBytes);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/src/cryfs/filesystem/fsblobstore/DirBlob.cpp new/src/cryfs/filesystem/fsblobstore/DirBlob.cpp
--- old/src/cryfs/filesystem/fsblobstore/DirBlob.cpp 2018-02-05 04:16:25.000000000 +0100
+++ new/src/cryfs/filesystem/fsblobstore/DirBlob.cpp 2019-01-21 04:39:01.000000000 +0100
@@ -29,18 +29,18 @@
constexpr off_t DirBlob::DIR_LSTAT_SIZE;
DirBlob::DirBlob(FsBlobStore *fsBlobStore, unique_ref<Blob> blob, std::function getLstatSize) :
- FsBlob(std::move(blob)), _fsBlobStore(fsBlobStore), _getLstatSize(getLstatSize), _entries(), _mutex(), _changed(false) {
+ FsBlob(std::move(blob)), _fsBlobStore(fsBlobStore), _getLstatSize(getLstatSize), _getLstatSizeMutex(), _entries(), _entriesAndChangedMutex(), _changed(false) {
ASSERT(baseBlob().blobType() == FsBlobView::BlobType::DIR, "Loaded blob is not a directory");
_readEntriesFromBlob();
}
DirBlob::~DirBlob() {
- std::unique_lockstd::mutex lock(_mutex);
+ std::unique_lockstd::mutex lock(_entriesAndChangedMutex);
_writeEntriesToBlob();
}
void DirBlob::flush() {
- std::unique_lockstd::mutex lock(_mutex);
+ std::unique_lockstd::mutex lock(_entriesAndChangedMutex);
_writeEntriesToBlob();
baseBlob().flush();
}
@@ -66,17 +66,17 @@
}
void DirBlob::AddChildDir(const std::string &name, const Key &blobKey, mode_t mode, uid_t uid, gid_t gid, timespec lastAccessTime, timespec lastModificationTime) {
- std::unique_lockstd::mutex lock(_mutex);
+ std::unique_lockstd::mutex lock(_entriesAndChangedMutex);
_addChild(name, blobKey, fspp::Dir::EntryType::DIR, mode, uid, gid, lastAccessTime, lastModificationTime);
}
void DirBlob::AddChildFile(const std::string &name, const Key &blobKey, mode_t mode, uid_t uid, gid_t gid, timespec lastAccessTime, timespec lastModificationTime) {
- std::unique_lockstd::mutex lock(_mutex);
+ std::unique_lockstd::mutex lock(_entriesAndChangedMutex);
_addChild(name, blobKey, fspp::Dir::EntryType::FILE, mode, uid, gid, lastAccessTime, lastModificationTime);
}
void DirBlob::AddChildSymlink(const std::string &name, const blockstore::Key &blobKey, uid_t uid, gid_t gid, timespec lastAccessTime, timespec lastModificationTime) {
- std::unique_lockstd::mutex lock(_mutex);
+ std::unique_lockstd::mutex lock(_entriesAndChangedMutex);
_addChild(name, blobKey, fspp::Dir::EntryType::SYMLINK, S_IFLNK | S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH, uid, gid, lastAccessTime, lastModificationTime);
}
@@ -89,41 +89,41 @@
void DirBlob::AddOrOverwriteChild(const std::string &name, const Key &blobKey, fspp::Dir::EntryType entryType,
mode_t mode, uid_t uid, gid_t gid, timespec lastAccessTime, timespec lastModificationTime,
std::function onOverwritten) {
- std::unique_lockstd::mutex lock(_mutex);
+ std::unique_lockstd::mutex lock(_entriesAndChangedMutex);
_entries.addOrOverwrite(name, blobKey, entryType, mode, uid, gid, lastAccessTime, lastModificationTime, onOverwritten);
_changed = true;
}
void DirBlob::RenameChild(const blockstore::Key &key, const std::string &newName, std::function onOverwritten) {
- std::unique_lockstd::mutex lock(_mutex);
+ std::unique_lockstd::mutex lock(_entriesAndChangedMutex);
_entries.rename(key, newName, onOverwritten);
_changed = true;
}
boost::optional DirBlob::GetChild(const string &name) const {
- std::unique_lockstd::mutex lock(_mutex);
+ std::unique_lockstd::mutex lock(_entriesAndChangedMutex);
return _entries.get(name);
}
boost::optional DirBlob::GetChild(const Key &key) const {
- std::unique_lockstd::mutex lock(_mutex);
+ std::unique_lockstd::mutex lock(_entriesAndChangedMutex);
return _entries.get(key);
}
void DirBlob::RemoveChild(const string &name) {
- std::unique_lockstd::mutex lock(_mutex);
+ std::unique_lockstd::mutex lock(_entriesAndChangedMutex);
_entries.remove(name);
_changed = true;
}
void DirBlob::RemoveChild(const Key &key) {
- std::unique_lockstd::mutex lock(_mutex);
+ std::unique_lockstd::mutex lock(_entriesAndChangedMutex);
_entries.remove(key);
_changed = true;
}
void DirBlob::AppendChildrenTo(vectorfspp::Dir::Entry *result) const {
- std::unique_lockstd::mutex lock(_mutex);
+ std::unique_lockstd::mutex lock(_entriesAndChangedMutex);
result->reserve(result->size() + _entries.size());
for (const auto &entry : _entries) {
result->emplace_back(entry.type(), entry.name());
@@ -135,7 +135,17 @@
}
void DirBlob::statChild(const Key &key, struct ::stat *result) const {
- result->st_size = _getLstatSize(key);
+ std::unique_lockstd::mutex lock(_getLstatSizeMutex);
+ auto lstatSizeGetter = _getLstatSize;
+
+ // The following unlock is important to avoid deadlock.
+ // ParallelAccessFsBlobStore::load() causes a call to DirBlob::setLstatSizeGetter,
+ // so their lock ordering first locks the ParallelAccessStore::_mutex, then the DirBlob::_getLstatSizeMutex.
+ // this requires us to free DirBlob::_getLstatSizeMutex before calling into lstatSizeGetter(), because
+ // lstatSizeGetter can call ParallelAccessFsBlobStore::load().
+ lock.unlock();
+
+ result->st_size = lstatSizeGetter(key);
statChildWithSizeAlreadySet(key, result);
}
@@ -159,43 +169,43 @@
}
void DirBlob::updateAccessTimestampForChild(const Key &key) {
- std::unique_lockstd::mutex lock(_mutex);
+ std::unique_lockstd::mutex lock(_entriesAndChangedMutex);
_entries.updateAccessTimestampForChild(key);
_changed = true;
}
void DirBlob::updateModificationTimestampForChild(const Key &key) {
- std::unique_lockstd::mutex lock(_mutex);
+ std::unique_lockstd::mutex lock(_entriesAndChangedMutex);
_entries.updateModificationTimestampForChild(key);
_changed = true;
}
void DirBlob::chmodChild(const Key &key, mode_t mode) {
- std::unique_lockstd::mutex lock(_mutex);
+ std::unique_lockstd::mutex lock(_entriesAndChangedMutex);
_entries.setMode(key, mode);
_changed = true;
}
void DirBlob::chownChild(const Key &key, uid_t uid, gid_t gid) {
- std::unique_lockstd::mutex lock(_mutex);
+ std::unique_lockstd::mutex lock(_entriesAndChangedMutex);
if(_entries.setUidGid(key, uid, gid)) {
_changed = true;
}
}
void DirBlob::utimensChild(const Key &key, timespec lastAccessTime, timespec lastModificationTime) {
- std::unique_lockstd::mutex lock(_mutex);
+ std::unique_lockstd::mutex lock(_entriesAndChangedMutex);
_entries.setAccessTimes(key, lastAccessTime, lastModificationTime);
_changed = true;
}
void DirBlob::setLstatSizeGetter(std::function getLstatSize) {
- std::unique_lockstd::mutex lock(_mutex);
+ std::unique_lockstd::mutex lock(_getLstatSizeMutex);
_getLstatSize = getLstatSize;
}
cpputils::unique_refblobstore::Blob DirBlob::releaseBaseBlob() {
- std::unique_lockstd::mutex lock(_mutex);
+ std::unique_lockstd::mutex lock(_entriesAndChangedMutex);
_writeEntriesToBlob();
return FsBlob::releaseBaseBlob();
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/src/cryfs/filesystem/fsblobstore/DirBlob.h new/src/cryfs/filesystem/fsblobstore/DirBlob.h
--- old/src/cryfs/filesystem/fsblobstore/DirBlob.h 2018-02-05 04:16:25.000000000 +0100
+++ new/src/cryfs/filesystem/fsblobstore/DirBlob.h 2019-01-21 04:39:01.000000000 +0100
@@ -82,8 +82,9 @@
FsBlobStore *_fsBlobStore;
std::function _getLstatSize;
+ mutable std::mutex _getLstatSizeMutex;
DirEntryList _entries;
- mutable std::mutex _mutex;
+ mutable std::mutex _entriesAndChangedMutex;
bool _changed;
DISALLOW_COPY_AND_ASSIGN(DirBlob);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/src/gitversion/_version.py new/src/gitversion/_version.py
--- old/src/gitversion/_version.py 2018-02-05 04:16:25.000000000 +0100
+++ new/src/gitversion/_version.py 2019-01-21 04:39:01.000000000 +0100
@@ -23,8 +23,8 @@
# setup.py/versioneer.py will grep for the variable names, so they must
# each be defined on a line of their own. _version.py will just call
# get_keywords().
- git_refnames = " (HEAD -> develop, tag: 0.9.9, origin/develop, origin/HEAD)"
- git_full = "fb792ec353a2fb93f7a61566e1d042fa7811f2a4"
+ git_refnames = " (HEAD -> release/0.9, tag: 0.9.10)"
+ git_full = "86600e725345b7864be2ca3c394d682996dc0814"
keywords = {"refnames": git_refnames, "full": git_full}
return keywords
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/test/blobstore/implementations/onblocks/BlobReadWriteTest.cpp new/test/blobstore/implementations/onblocks/BlobReadWriteTest.cpp
--- old/test/blobstore/implementations/onblocks/BlobReadWriteTest.cpp 2018-02-05 04:16:25.000000000 +0100
+++ new/test/blobstore/implementations/onblocks/BlobReadWriteTest.cpp 2019-01-21 04:39:01.000000000 +0100
@@ -63,6 +63,92 @@
EXPECT_EQ(32780u, blob->size());
}
+TEST_F(BlobReadWriteTest, givenEmptyBlob_whenTryReadInFirstLeaf_thenFails) {
+ Data data(5);
+ size_t read = blob->tryRead(data.data(), 3, 5);
+ EXPECT_EQ(0, read);
+}
+
+TEST_F(BlobReadWriteTest, givenEmptyBlob_whenTryReadInLaterLeaf_thenFails) {
+ Data data(5);
+ size_t read = blob->tryRead(data.data(), 2*LAYOUT.maxBytesPerLeaf(), 5);
+ EXPECT_EQ(0, read);
+}
+
+TEST_F(BlobReadWriteTest, givenEmptyBlob_whenReadInFirstLeaf_thenFails) {
+ Data data(5);
+ EXPECT_ANY_THROW(
+ blob->read(data.data(), 3, 5)
+ );
+}
+
+TEST_F(BlobReadWriteTest, givenEmptyBlob_whenReadInLaterLeaf_thenFails) {
+ Data data(5);
+ EXPECT_ANY_THROW(
+ blob->read(data.data(), 2*LAYOUT.maxBytesPerLeaf(), 5)
+ );
+}
+
+TEST_F(BlobReadWriteTest, givenEmptyBlob_whenReadAll_thenReturnsZeroSizedData) {
+ Data data = blob->readAll();
+ EXPECT_EQ(0, data.size());
+}
+
+TEST_F(BlobReadWriteTest, givenEmptyBlob_whenWrite_thenGrows) {
+ Data data(5);
+ blob->write(data.data(), 4, 5);
+ EXPECT_EQ(9, blob->size());
+}
+
+TEST_F(BlobReadWriteTest, givenEmptyBlob_whenWriteZeroBytes_thenDoesntGrow) {
+ Data data(5);
+ blob->write(data.data(), 4, 0);
+ EXPECT_EQ(0, blob->size());;
+}
+
+TEST_F(BlobReadWriteTest, givenBlobResizedToZero_whenTryReadInFirstLeaf_thenFails) {
+ Data data(5);
+ size_t read = blob->tryRead(data.data(), 3, 5);
+ EXPECT_EQ(0, read);
+}
+
+TEST_F(BlobReadWriteTest, givenBlobResizedToZero_whenTryReadInLaterLeaf_thenFails) {
+ Data data(5);
+ size_t read = blob->tryRead(data.data(), 2*LAYOUT.maxBytesPerLeaf(), 5);
+ EXPECT_EQ(0, read);
+}
+
+TEST_F(BlobReadWriteTest, givenBlobResizedToZero_whenReadInFirstLeaf_thenFails) {
+ Data data(5);
+ EXPECT_ANY_THROW(
+ blob->read(data.data(), 3, 5)
+ );
+}
+
+TEST_F(BlobReadWriteTest, givenBlobResizedToZero_whenReadInLaterLeaf_thenFails) {
+ Data data(5);
+ EXPECT_ANY_THROW(
+ blob->read(data.data(), 2*LAYOUT.maxBytesPerLeaf(), 5)
+ );
+}
+
+TEST_F(BlobReadWriteTest, givenBlobResizedToZero_whenReadAll_thenReturnsZeroSizedData) {
+ Data data = blob->readAll();
+ EXPECT_EQ(0, data.size());
+}
+
+TEST_F(BlobReadWriteTest, givenBlobResizedToZero_whenWrite_thenGrows) {
+ Data data(5);
+ blob->write(data.data(), 4, 5);
+ EXPECT_EQ(9, blob->size());
+}
+
+TEST_F(BlobReadWriteTest, givenBlobResizedToZero_whenWriteZeroBytes_thenDoesntGrow) {
+ Data data(5);
+ blob->write(data.data(), 4, 0);
+ EXPECT_EQ(0, blob->size());
+}
+
struct DataRange {
size_t blobsize;
off_t offset;