1
0
mirror of https://github.com/vgough/encfs.git synced 2025-01-14 01:48:30 +01:00

Implement --nocache

Disable block cache (in EncFS) and stat cache (in kernel).
This is needed if the backing files may be modified
behind the back of EncFS (for example, when you mount
an encrypted filesystem exported by encfs --reverse).

The reverse grow tests fail when this option is not passed to the
decrypting mount.
This commit is contained in:
Jakob Unterwurzacher 2014-11-17 21:57:06 +01:00
parent 9f9e30a73f
commit dee3f628e3
5 changed files with 41 additions and 19 deletions

View File

@ -27,6 +27,8 @@
#include "i18n.h"
#include "FileUtils.h"
template <typename Type>
inline Type min(Type A, Type B) {
return (B < A) ? B : A;
@ -41,6 +43,7 @@ BlockFileIO::BlockFileIO(int blockSize, const FSConfigPtr &cfg)
: _blockSize(blockSize), _allowHoles(cfg->config->allowHoles) {
rAssert(_blockSize > 1);
_cache.data = new unsigned char[_blockSize];
_noCache = cfg->opts->noCache;
}
BlockFileIO::~BlockFileIO() {
@ -61,8 +64,11 @@ ssize_t BlockFileIO::cacheReadOneBlock(const IORequest &req) const {
/* we can satisfy the request even if _cache.dataLen is too short, because
* we always request a full block during reads. This just means we are
* in the last block of a file, which may be smaller than the blocksize. */
if ((req.offset == _cache.offset) && (_cache.dataLen != 0)) {
* in the last block of a file, which may be smaller than the blocksize.
* For reverse encryption, the cache must not be used at all, because
* the lower file may have changed behind our back. */
if ( (_noCache == false) && (req.offset == _cache.offset) &&
(_cache.dataLen != 0)) {
// satisfy request from cache
int len = req.dataLen;
if (_cache.dataLen < len) len = _cache.dataLen; // Don't read past EOF

View File

@ -57,6 +57,7 @@ class BlockFileIO : public FileIO {
int _blockSize;
bool _allowHoles;
bool _noCache;
// cache last block for speed...
mutable IORequest _cache;

View File

@ -76,6 +76,11 @@ struct EncFS_Opts {
bool reverseEncryption; // Reverse encryption
bool noCache; /* Disable block cache (in EncFS) and stat cache (in kernel).
* This is needed if the backing files may be modified
* behind the back of EncFS (for example, in reverse mode).
* See main.cpp for a longer explaination. */
ConfigMode configMode;
EncFS_Opts() {
@ -90,6 +95,7 @@ struct EncFS_Opts {
ownerCreate = false;
reverseEncryption = false;
configMode = Config_Prompt;
noCache = false;
}
};

View File

@ -212,6 +212,7 @@ static bool processArgs(int argc, char *argv[],
// {"single-thread", 0, 0, 's'}, // single-threaded mode
{"stdinpass", 0, 0, 'S'}, // read password from stdin
{"annotate", 0, 0, 513}, // Print annotation lines to stderr
{"nocache", 0, 0, 514}, // disable caching
{"verbose", 0, 0, 'v'}, // verbose mode
{"version", 0, 0, 'V'}, // version
{"reverse", 0, 0, 'r'}, // reverse encryption
@ -272,24 +273,32 @@ static bool processArgs(int argc, char *argv[],
case 'D':
out->opts->forceDecode = true;
break;
/* By default, the kernel caches file metadata for one second.
* This is fine for EncFS' normal mode, but for --reverse, this
* means that the encrypted view will be up to one second out of
* date.
* Quoting Goswin von Brederlow:
* "Caching only works correctly if you implement a disk based
* filesystem, one where only the fuse process can alter
* metadata and all access goes only through fuse. Any overlay
* filesystem where something can change the underlying
* filesystem without going through fuse can run into
* inconsistencies."
* Enabling reverse automatically enables noCache. */
case 'r':
out->opts->reverseEncryption = true;
/* By default, the kernel caches file metadata for one second.
* This is fine for EncFS' normal mode, but for --reverse, this
* means that the encrypted view will be up to one second out of
* date.
* Quoting Goswin von Brederlow:
* "Caching only works correctly if you implement a disk based
* filesystem, one where only the fuse process can alter
* metadata and all access goes only through fuse. Any overlay
* filesystem where something can change the underlying
* filesystem without going through fuse can run into
* inconsistencies."
* Disable caching so the encrypted view stays consistent with
* the backing files. */
PUSHARG("-oattr_timeout=0"); // Causes reverse grow tests to fail
// because stale stat() data is returned
PUSHARG("-oentry_timeout=0"); // Fallout unknown, disabling for safety
case 514:
/* Disable EncFS block cache
* Causes reverse grow tests to fail because short reads
* are returned */
out->opts->noCache = true;
/* Disable kernel stat() cache
* Causes reverse grow tests to fail because stale stat() data
* is returned */
PUSHARG("-oattr_timeout=0");
/* Disable kernel dentry cache
* Fallout unknown, disabling for safety */
PUSHARG("-oentry_timeout=0");
break;
case 'm':
out->opts->mountOnDemand = true;

View File

@ -48,7 +48,7 @@ sub mount
ok(waitForFile("$plain/.encfs6.xml"), "plain .encfs6.xml exists") or BAIL_OUT("'$plain/.encfs6.xml'");
my $e = encName(".encfs6.xml");
ok(waitForFile("$ciphertext/$e"), "encrypted .encfs6.xml exists") or BAIL_OUT("'$ciphertext/$e'");
system("ENCFS6_CONFIG=$plain/.encfs6.xml ./encfs/encfs -o attr_timeout=0 --extpass=\"echo test\" $ciphertext $decrypted");
system("ENCFS6_CONFIG=$plain/.encfs6.xml ./encfs/encfs --nocache --extpass=\"echo test\" $ciphertext $decrypted");
ok(waitForFile("$decrypted/.encfs6.xml"), "decrypted .encfs6.xml exists") or BAIL_OUT("'$decrypted/.encfs6.xml'");
}