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 <[email protected]>
+
+- 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 <[email protected]>
 #
 # 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_lock<std::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_lock<std::mutex> lock(_datatree->mutex());
+
   _datatree->resizeNumBytes(numBytes);
   _sizeCache = numBytes;
 }
 
-void BlobOnBlocks::traverseLeaves(uint64_t beginByte, uint64_t sizeBytes, 
function<void (uint64_t, DataLeafNode *leaf, uint32_t, uint32_t)> func) const {
+void BlobOnBlocks::_traverseLeaves(uint64_t beginByte, uint64_t sizeBytes, 
function<void (uint64_t, DataLeafNode *leaf, uint32_t, uint32_t)> 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_lock<std::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_lock<std::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_lock<std::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<int64_t>(count), 
static_cast<int64_t>(_size())-static_cast<int64_t>(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_lock<std::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_lock<std::mutex> lock(_datatree->mutex());
+
   _datatree->flush();
 }
 
@@ -102,6 +138,8 @@
 }
 
 unique_ref<DataTreeRef> BlobOnBlocks::releaseTree() {
+  std::unique_lock<std::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<void (uint64_t, datanodestore::DataLeafNode *, uint32_t, 
uint32_t)>) const;
+  uint64_t _tryRead(void *target, uint64_t offset, uint64_t size) const;
+  void _traverseLeaves(uint64_t offsetBytes, uint64_t sizeBytes, 
std::function<void (uint64_t, datanodestore::DataLeafNode *, uint32_t, 
uint32_t)>) const;
 
   cpputils::unique_ref<parallelaccessdatatreestore::DataTreeRef> _datatree;
   mutable boost::optional<uint64_t> _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<void (DataLeafNode*, uint32_t)> func) {
+  if (endIndex <= beginIndex) {
+      return;
+  }
+  
   //TODO Can we traverse in parallel?
   unique_lock<shared_mutex> 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_ref<datanodestore::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_lock<boost::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<off_t (const blockstore::Key&)> 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_lock<std::mutex> lock(_mutex);
+  std::unique_lock<std::mutex> lock(_entriesAndChangedMutex);
   _writeEntriesToBlob();
 }
 
 void DirBlob::flush() {
-  std::unique_lock<std::mutex> lock(_mutex);
+  std::unique_lock<std::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_lock<std::mutex> lock(_mutex);
+  std::unique_lock<std::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_lock<std::mutex> lock(_mutex);
+  std::unique_lock<std::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_lock<std::mutex> lock(_mutex);
+  std::unique_lock<std::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<void (const blockstore::Key 
&key)> onOverwritten) {
-  std::unique_lock<std::mutex> lock(_mutex);
+  std::unique_lock<std::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<void (const blockstore::Key &key)> onOverwritten) {
-  std::unique_lock<std::mutex> lock(_mutex);
+  std::unique_lock<std::mutex> lock(_entriesAndChangedMutex);
   _entries.rename(key, newName, onOverwritten);
   _changed = true;
 }
 
 boost::optional<const DirEntry&> DirBlob::GetChild(const string &name) const {
-  std::unique_lock<std::mutex> lock(_mutex);
+  std::unique_lock<std::mutex> lock(_entriesAndChangedMutex);
   return _entries.get(name);
 }
 
 boost::optional<const DirEntry&> DirBlob::GetChild(const Key &key) const {
-  std::unique_lock<std::mutex> lock(_mutex);
+  std::unique_lock<std::mutex> lock(_entriesAndChangedMutex);
   return _entries.get(key);
 }
 
 void DirBlob::RemoveChild(const string &name) {
-  std::unique_lock<std::mutex> lock(_mutex);
+  std::unique_lock<std::mutex> lock(_entriesAndChangedMutex);
   _entries.remove(name);
   _changed = true;
 }
 
 void DirBlob::RemoveChild(const Key &key) {
-  std::unique_lock<std::mutex> lock(_mutex);
+  std::unique_lock<std::mutex> lock(_entriesAndChangedMutex);
   _entries.remove(key);
   _changed = true;
 }
 
 void DirBlob::AppendChildrenTo(vector<fspp::Dir::Entry> *result) const {
-  std::unique_lock<std::mutex> lock(_mutex);
+  std::unique_lock<std::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_lock<std::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_lock<std::mutex> lock(_mutex);
+  std::unique_lock<std::mutex> lock(_entriesAndChangedMutex);
   _entries.updateAccessTimestampForChild(key);
   _changed = true;
 }
 
 void DirBlob::updateModificationTimestampForChild(const Key &key) {
-  std::unique_lock<std::mutex> lock(_mutex);
+  std::unique_lock<std::mutex> lock(_entriesAndChangedMutex);
   _entries.updateModificationTimestampForChild(key);
   _changed = true;
 }
 
 void DirBlob::chmodChild(const Key &key, mode_t mode) {
-  std::unique_lock<std::mutex> lock(_mutex);
+  std::unique_lock<std::mutex> lock(_entriesAndChangedMutex);
   _entries.setMode(key, mode);
   _changed = true;
 }
 
 void DirBlob::chownChild(const Key &key, uid_t uid, gid_t gid) {
-  std::unique_lock<std::mutex> lock(_mutex);
+  std::unique_lock<std::mutex> lock(_entriesAndChangedMutex);
   if(_entries.setUidGid(key, uid, gid)) {
     _changed = true;
   }
 }
 
 void DirBlob::utimensChild(const Key &key, timespec lastAccessTime, timespec 
lastModificationTime) {
-  std::unique_lock<std::mutex> lock(_mutex);
+  std::unique_lock<std::mutex> lock(_entriesAndChangedMutex);
   _entries.setAccessTimes(key, lastAccessTime, lastModificationTime);
   _changed = true;
 }
 
 void DirBlob::setLstatSizeGetter(std::function<off_t(const blockstore::Key&)> 
getLstatSize) {
-    std::unique_lock<std::mutex> lock(_mutex);
+    std::unique_lock<std::mutex> lock(_getLstatSizeMutex);
     _getLstatSize = getLstatSize;
 }
 
 cpputils::unique_ref<blobstore::Blob> DirBlob::releaseBaseBlob() {
-  std::unique_lock<std::mutex> lock(_mutex);
+  std::unique_lock<std::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<off_t (const blockstore::Key&)> _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;


Reply via email to