mirror of
https://github.com/vgough/encfs.git
synced 2024-11-25 09:23:13 +01:00
add zero-block pass-through option, enabling allow-holes code
git-svn-id: http://encfs.googlecode.com/svn/trunk@14 db9cf616-1c43-0410-9cb8-a902689de0d6
This commit is contained in:
parent
9ce4a03887
commit
30ed7062d3
@ -189,7 +189,7 @@ bool BlockFileIO::write( const IORequest &req )
|
|||||||
if(lastBlockSize == 0)
|
if(lastBlockSize == 0)
|
||||||
--lastNonEmptyBlock;
|
--lastNonEmptyBlock;
|
||||||
|
|
||||||
if( (req.offset > fileSize) && !_allowHoles )
|
if( req.offset > fileSize )
|
||||||
{
|
{
|
||||||
// extend file first to fill hole with 0's..
|
// extend file first to fill hole with 0's..
|
||||||
const bool forceWrite = false;
|
const bool forceWrite = false;
|
||||||
@ -340,15 +340,18 @@ void BlockFileIO::padFile( off_t oldSize, off_t newSize, bool forceWrite )
|
|||||||
++oldLastBlock;
|
++oldLastBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2
|
// 2, pad zero blocks unless holes are allowed
|
||||||
for(; oldLastBlock != newLastBlock; ++oldLastBlock)
|
if(!_allowHoles)
|
||||||
{
|
{
|
||||||
rDebug("padding block %" PRIi64, oldLastBlock);
|
for(; oldLastBlock != newLastBlock; ++oldLastBlock)
|
||||||
req.offset = oldLastBlock * _blockSize;
|
{
|
||||||
req.dataLen = _blockSize;
|
rDebug("padding block %" PRIi64, oldLastBlock);
|
||||||
memset( mb.data, 0, req.dataLen );
|
req.offset = oldLastBlock * _blockSize;
|
||||||
cacheWriteOneBlock( req );
|
req.dataLen = _blockSize;
|
||||||
}
|
memset( mb.data, 0, req.dataLen );
|
||||||
|
cacheWriteOneBlock( req );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 3. only necessary if write is forced and block is non 0 length
|
// 3. only necessary if write is forced and block is non 0 length
|
||||||
if(forceWrite && newBlockSize)
|
if(forceWrite && newBlockSize)
|
||||||
|
@ -40,12 +40,12 @@ public:
|
|||||||
|
|
||||||
virtual int blockSize() const;
|
virtual int blockSize() const;
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
// default is false, but setting this to true will allow holes to be stored
|
// default is false, but setting this to true will allow holes to be stored
|
||||||
// in the file. Only works if supported by the underlying FileIO
|
// in the file. Only works if supported by the underlying FileIO
|
||||||
// implementation..
|
// implementation..
|
||||||
void allowHoles( bool allow );
|
virtual void allowHoles( bool allow );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
int truncate( off_t size, FileIO *base );
|
int truncate( off_t size, FileIO *base );
|
||||||
void padFile( off_t oldSize, off_t newSize, bool forceWrite );
|
void padFile( off_t oldSize, off_t newSize, bool forceWrite );
|
||||||
|
@ -372,7 +372,18 @@ bool CipherFileIO::blockRead( unsigned char *buf, int size,
|
|||||||
if (reverseEncryption)
|
if (reverseEncryption)
|
||||||
return cipher->blockEncode( buf, size, _iv64, key );
|
return cipher->blockEncode( buf, size, _iv64, key );
|
||||||
else
|
else
|
||||||
return cipher->blockDecode( buf, size, _iv64, key );
|
{
|
||||||
|
if(_allowHoles)
|
||||||
|
{
|
||||||
|
// special case - leave all 0's alone
|
||||||
|
for(int i=0; i<size; ++i)
|
||||||
|
if(buf[i] != 0)
|
||||||
|
return cipher->blockDecode( buf, size, _iv64, key );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else
|
||||||
|
return cipher->blockDecode( buf, size, _iv64, key );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CipherFileIO::streamRead( unsigned char *buf, int size,
|
bool CipherFileIO::streamRead( unsigned char *buf, int size,
|
||||||
|
@ -726,7 +726,8 @@ shared_ptr<FileNode> DirNode::findOrCreate( const char *plainName)
|
|||||||
config->uniqueIV,
|
config->uniqueIV,
|
||||||
config->externalIVChaining,
|
config->externalIVChaining,
|
||||||
config->forceDecode,
|
config->forceDecode,
|
||||||
config->reverseEncryption) );
|
config->reverseEncryption,
|
||||||
|
config->allowHoles) );
|
||||||
|
|
||||||
if(config->externalIVChaining)
|
if(config->externalIVChaining)
|
||||||
node->setName(0, 0, iv);
|
node->setName(0, 0, iv);
|
||||||
|
@ -101,6 +101,7 @@ public:
|
|||||||
bool externalIVChaining;
|
bool externalIVChaining;
|
||||||
bool forceDecode; // force decoding, even if errors are detected
|
bool forceDecode; // force decoding, even if errors are detected
|
||||||
bool reverseEncryption;
|
bool reverseEncryption;
|
||||||
|
bool allowHoles; // allow holes in files
|
||||||
Config()
|
Config()
|
||||||
: fsSubVersion(0)
|
: fsSubVersion(0)
|
||||||
, blockSize(1)
|
, blockSize(1)
|
||||||
@ -111,6 +112,7 @@ public:
|
|||||||
, externalIVChaining( false )
|
, externalIVChaining( false )
|
||||||
, forceDecode( false )
|
, forceDecode( false )
|
||||||
, reverseEncryption ( false )
|
, reverseEncryption ( false )
|
||||||
|
, allowHoles( false )
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace rel;
|
using namespace rel;
|
||||||
using namespace rlog;
|
using namespace rlog;
|
||||||
|
using boost::dynamic_pointer_cast;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO: locking at the FileNode level is inefficient, since this precludes
|
TODO: locking at the FileNode level is inefficient, since this precludes
|
||||||
@ -65,7 +66,8 @@ FileNode::FileNode(DirNode *parent_,
|
|||||||
const char *plaintextName_, const char *cipherName_,
|
const char *plaintextName_, const char *cipherName_,
|
||||||
const shared_ptr<Cipher> &dataCipher, const CipherKey &key,
|
const shared_ptr<Cipher> &dataCipher, const CipherKey &key,
|
||||||
int blockSize, int blockMACBytes, int blockMACRandBytes, bool uniqueIV,
|
int blockSize, int blockMACBytes, int blockMACRandBytes, bool uniqueIV,
|
||||||
bool externalIVChaining_, bool forceDecode, bool reverseEncryption_ )
|
bool externalIVChaining_, bool forceDecode, bool reverseEncryption_,
|
||||||
|
bool allowHoles )
|
||||||
{
|
{
|
||||||
pthread_mutex_init( &mutex, 0 );
|
pthread_mutex_init( &mutex, 0 );
|
||||||
|
|
||||||
@ -88,6 +90,9 @@ FileNode::FileNode(DirNode *parent_,
|
|||||||
io = shared_ptr<FileIO>(new MACFileIO(io, dataCipher, key,
|
io = shared_ptr<FileIO>(new MACFileIO(io, dataCipher, key,
|
||||||
blockSize,blockMACBytes,blockMACRandBytes,forceDecode));
|
blockSize,blockMACBytes,blockMACRandBytes,forceDecode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(allowHoles)
|
||||||
|
dynamic_pointer_cast<BlockFileIO>(io)->allowHoles( allowHoles );
|
||||||
}
|
}
|
||||||
|
|
||||||
FileNode::~FileNode()
|
FileNode::~FileNode()
|
||||||
|
@ -43,7 +43,8 @@ public:
|
|||||||
bool uniqueIV, // enable per-file initialization vectors
|
bool uniqueIV, // enable per-file initialization vectors
|
||||||
bool externalIVChaining,
|
bool externalIVChaining,
|
||||||
bool forceDecode, // decode, even if decoding errors are detected
|
bool forceDecode, // decode, even if decoding errors are detected
|
||||||
bool reverseEncryption );
|
bool reverseEncryption,
|
||||||
|
bool allowHoles );
|
||||||
~FileNode();
|
~FileNode();
|
||||||
|
|
||||||
const char *plaintextName() const;
|
const char *plaintextName() const;
|
||||||
|
@ -271,7 +271,9 @@ bool readV5Config( const char *configFile, EncFSConfig *config,
|
|||||||
config->blockMACBytes = cfgRdr["blockMACBytes"].readInt(0);
|
config->blockMACBytes = cfgRdr["blockMACBytes"].readInt(0);
|
||||||
config->blockMACRandBytes =
|
config->blockMACRandBytes =
|
||||||
cfgRdr["blockMACRandBytes"].readInt(0);
|
cfgRdr["blockMACRandBytes"].readInt(0);
|
||||||
|
|
||||||
|
config->allowHoles = cfgRdr["allowHoles"].readBool( false );
|
||||||
|
|
||||||
ok = true;
|
ok = true;
|
||||||
} catch( rlog::Error &err)
|
} catch( rlog::Error &err)
|
||||||
{
|
{
|
||||||
@ -411,6 +413,7 @@ bool writeV5Config( const char *configFile, EncFSConfig *config )
|
|||||||
cfg["uniqueIV"] << config->uniqueIV;
|
cfg["uniqueIV"] << config->uniqueIV;
|
||||||
cfg["chainedIV"] << config->chainedNameIV;
|
cfg["chainedIV"] << config->chainedNameIV;
|
||||||
cfg["externalIV"] << config->externalIVChaining;
|
cfg["externalIV"] << config->externalIVChaining;
|
||||||
|
cfg["allowHoles"] << config->allowHoles;
|
||||||
|
|
||||||
return cfg.save( configFile );
|
return cfg.save( configFile );
|
||||||
}
|
}
|
||||||
@ -679,23 +682,35 @@ int selectBlockSize( const Cipher::CipherAlgorithm &alg )
|
|||||||
return blockSize;
|
return blockSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void selectBlockMAC(int *macBytes, int *macRandBytes)
|
bool boolDefaultNo(const char *prompt)
|
||||||
{
|
{
|
||||||
// xgroup(setup)
|
cout << prompt << "\n";
|
||||||
cout << _("Enable block authentication code headers\n"
|
cout << _("The default here is No.\n"
|
||||||
"on every block in a file? This adds about 12 bytes per block\n"
|
"Any response that does not begin with 'y' will mean No: ");
|
||||||
"to the storage requirements for a file, and significantly affects\n"
|
|
||||||
"performance but it also means [almost] any modifications or errors\n"
|
|
||||||
"within a block will be caught and will cause a read error.\n"
|
|
||||||
"The default here is No. \n"
|
|
||||||
"Any response that does not begin with 'y' will mean No: ");
|
|
||||||
|
|
||||||
char answer[10];
|
char answer[10];
|
||||||
fgets( answer, sizeof(answer), stdin );
|
fgets( answer, sizeof(answer), stdin );
|
||||||
cout << "\n";
|
cout << "\n";
|
||||||
|
|
||||||
if(tolower(answer[0]) == 'y')
|
if(tolower(answer[0]) == 'n')
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void selectBlockMAC(int *macBytes, int *macRandBytes)
|
||||||
|
{
|
||||||
|
// xgroup(setup)
|
||||||
|
bool addMAC = boolDefaultNo(
|
||||||
|
_("Enable block authentication code headers\n"
|
||||||
|
"on every block in a file? This adds about 12 bytes per block\n"
|
||||||
|
"to the storage requirements for a file, and significantly affects\n"
|
||||||
|
"performance but it also means [almost] any modifications or errors\n"
|
||||||
|
"within a block will be caught and will cause a read error."));
|
||||||
|
|
||||||
|
if(addMAC)
|
||||||
{
|
{
|
||||||
*macBytes = 8;
|
*macBytes = 8;
|
||||||
|
|
||||||
@ -707,7 +722,8 @@ void selectBlockMAC(int *macBytes, int *macRandBytes)
|
|||||||
"vectors, which does not come with as great of performance\n"
|
"vectors, which does not come with as great of performance\n"
|
||||||
"penalty. \n"
|
"penalty. \n"
|
||||||
"Select a number of bytes, from 0 (no random bytes) to 8: ");
|
"Select a number of bytes, from 0 (no random bytes) to 8: ");
|
||||||
|
|
||||||
|
char answer[10];
|
||||||
int randSize = 0;
|
int randSize = 0;
|
||||||
fgets( answer, sizeof(answer), stdin );
|
fgets( answer, sizeof(answer), stdin );
|
||||||
cout << "\n";
|
cout << "\n";
|
||||||
@ -726,59 +742,12 @@ void selectBlockMAC(int *macBytes, int *macRandBytes)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
bool selectUniqueIV()
|
bool boolDefaultYes(const char *prompt)
|
||||||
{
|
{
|
||||||
// xgroup(setup)
|
cout << prompt << "\n";
|
||||||
cout << _("Enable per-file initialization vectors?\n"
|
cout << _("The default here is Yes.\n"
|
||||||
"This adds about 8 bytes per file to the storage requirements.\n"
|
"Any response that does not begin with 'n' will mean Yes: ");
|
||||||
"It should not affect performance except possibly with applications\n"
|
|
||||||
"which rely on block-aligned file io for performance.\n"
|
|
||||||
"The default here is Yes. \n"
|
|
||||||
"Any response that does not begin with 'n' will mean Yes: ");
|
|
||||||
|
|
||||||
char answer[10];
|
|
||||||
fgets( answer, sizeof(answer), stdin );
|
|
||||||
cout << "\n";
|
|
||||||
|
|
||||||
if(tolower(answer[0]) == 'n')
|
|
||||||
return false;
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
bool selectChainedIV()
|
|
||||||
{
|
|
||||||
// xgroup(setup)
|
|
||||||
cout << _("Enable filename initialization vector chaining?\n"
|
|
||||||
"This makes filename encoding dependent on the complete path, \n"
|
|
||||||
"rather then encoding each path element individually. \n"
|
|
||||||
"This is normally desireable, therefor the default is Yes. \n"
|
|
||||||
"Any response that does not begin with 'n' will mean Yes: ");
|
|
||||||
|
|
||||||
char answer[10];
|
|
||||||
fgets( answer, sizeof(answer), stdin );
|
|
||||||
cout << "\n";
|
|
||||||
|
|
||||||
if(tolower(answer[0]) == 'n')
|
|
||||||
return false;
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
bool selectExternalChainedIV()
|
|
||||||
{
|
|
||||||
// xgroup(setup)
|
|
||||||
cout << _("Enable filename to IV header chaining?\n"
|
|
||||||
"This makes file data encoding dependent on the complete file path.\n"
|
|
||||||
"If a file is renamed, it will not decode sucessfully unless it\n"
|
|
||||||
"was renamed by encfs with the proper key.\n"
|
|
||||||
"If this option is enabled, then hard links will not be supported\n"
|
|
||||||
"in the filesystem.\n"
|
|
||||||
"The default is No. \n"
|
|
||||||
"Any response that does not begin with 'y' will mean No: ");
|
|
||||||
|
|
||||||
char answer[10];
|
char answer[10];
|
||||||
fgets( answer, sizeof(answer), stdin );
|
fgets( answer, sizeof(answer), stdin );
|
||||||
@ -790,6 +759,49 @@ bool selectExternalChainedIV()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
bool selectUniqueIV()
|
||||||
|
{
|
||||||
|
// xgroup(setup)
|
||||||
|
return boolDefaultYes(
|
||||||
|
_("Enable per-file initialization vectors?\n"
|
||||||
|
"This adds about 8 bytes per file to the storage requirements.\n"
|
||||||
|
"It should not affect performance except possibly with applications\n"
|
||||||
|
"which rely on block-aligned file io for performance."));
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
bool selectChainedIV()
|
||||||
|
{
|
||||||
|
// xgroup(setup)
|
||||||
|
return boolDefaultYes(
|
||||||
|
_("Enable filename initialization vector chaining?\n"
|
||||||
|
"This makes filename encoding dependent on the complete path, \n"
|
||||||
|
"rather then encoding each path element individually."));
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
bool selectExternalChainedIV()
|
||||||
|
{
|
||||||
|
// xgroup(setup)
|
||||||
|
return boolDefaultNo(
|
||||||
|
_("Enable filename to IV header chaining?\n"
|
||||||
|
"This makes file data encoding dependent on the complete file path.\n"
|
||||||
|
"If a file is renamed, it will not decode sucessfully unless it\n"
|
||||||
|
"was renamed by encfs with the proper key.\n"
|
||||||
|
"If this option is enabled, then hard links will not be supported\n"
|
||||||
|
"in the filesystem."));
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
bool selectZeroBlockPassThrough()
|
||||||
|
{
|
||||||
|
// xgroup(setup)
|
||||||
|
return boolDefaultNo(
|
||||||
|
_("Enable file-hole pass-through?\n"
|
||||||
|
"This avoids writing encrypted blocks when file holes are created."));
|
||||||
|
}
|
||||||
|
|
||||||
RootPtr createV5Config( EncFS_Context *ctx, const std::string &rootDir,
|
RootPtr createV5Config( EncFS_Context *ctx, const std::string &rootDir,
|
||||||
bool enableIdleTracking, bool forceDecode,
|
bool enableIdleTracking, bool forceDecode,
|
||||||
const std::string &passwordProgram,
|
const std::string &passwordProgram,
|
||||||
@ -822,6 +834,7 @@ RootPtr createV5Config( EncFS_Context *ctx, const std::string &rootDir,
|
|||||||
bool uniqueIV = false;
|
bool uniqueIV = false;
|
||||||
bool chainedIV = false;
|
bool chainedIV = false;
|
||||||
bool externalIV = false;
|
bool externalIV = false;
|
||||||
|
bool allowHoles = false;
|
||||||
|
|
||||||
if (reverseEncryption)
|
if (reverseEncryption)
|
||||||
{
|
{
|
||||||
@ -861,13 +874,11 @@ RootPtr createV5Config( EncFS_Context *ctx, const std::string &rootDir,
|
|||||||
{
|
{
|
||||||
// xgroup(setup)
|
// xgroup(setup)
|
||||||
cout << _("Standard configuration selected.") << "\n";
|
cout << _("Standard configuration selected.") << "\n";
|
||||||
// look for blowfish with 160 bit key..
|
// AES w/ 192 bit key, block name encoding, per-file initialization
|
||||||
// block name encoding is now standard as well..
|
// vectors are all standard.
|
||||||
// per-file initialization vectors are now standard, as they shouldn't
|
keySize = 192;
|
||||||
// have any significant performance penalty.
|
|
||||||
keySize = 160;
|
|
||||||
blockSize = DefaultBlockSize;
|
blockSize = DefaultBlockSize;
|
||||||
alg = findCipherAlgorithm("Blowfish", keySize);
|
alg = findCipherAlgorithm("AES", keySize);
|
||||||
blockMACBytes = 0;
|
blockMACBytes = 0;
|
||||||
externalIV = false;
|
externalIV = false;
|
||||||
nameIOIface = BlockNameIO::CurrentInterface();
|
nameIOIface = BlockNameIO::CurrentInterface();
|
||||||
@ -917,10 +928,11 @@ RootPtr createV5Config( EncFS_Context *ctx, const std::string &rootDir,
|
|||||||
// xgroup(setup)
|
// xgroup(setup)
|
||||||
cout << _("External chained IV disabled, as both 'IV chaining'\n"
|
cout << _("External chained IV disabled, as both 'IV chaining'\n"
|
||||||
"and 'unique IV' features are required for this option.")
|
"and 'unique IV' features are required for this option.")
|
||||||
<< endl;
|
<< "\n";
|
||||||
externalIV = false;
|
externalIV = false;
|
||||||
}
|
}
|
||||||
selectBlockMAC(&blockMACBytes, &blockMACRandBytes);
|
selectBlockMAC(&blockMACBytes, &blockMACRandBytes);
|
||||||
|
allowHoles = selectZeroBlockPassThrough();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -949,6 +961,7 @@ RootPtr createV5Config( EncFS_Context *ctx, const std::string &rootDir,
|
|||||||
config.uniqueIV = uniqueIV;
|
config.uniqueIV = uniqueIV;
|
||||||
config.chainedNameIV = chainedIV;
|
config.chainedNameIV = chainedIV;
|
||||||
config.externalIVChaining = externalIV;
|
config.externalIVChaining = externalIV;
|
||||||
|
config.allowHoles = allowHoles;
|
||||||
|
|
||||||
cout << "\n";
|
cout << "\n";
|
||||||
// xgroup(setup)
|
// xgroup(setup)
|
||||||
@ -1035,6 +1048,7 @@ RootPtr createV5Config( EncFS_Context *ctx, const std::string &rootDir,
|
|||||||
dirNodeConfig->externalIVChaining = config.externalIVChaining;
|
dirNodeConfig->externalIVChaining = config.externalIVChaining;
|
||||||
dirNodeConfig->forceDecode = forceDecode;
|
dirNodeConfig->forceDecode = forceDecode;
|
||||||
dirNodeConfig->reverseEncryption = reverseEncryption;
|
dirNodeConfig->reverseEncryption = reverseEncryption;
|
||||||
|
dirNodeConfig->allowHoles = config.allowHoles;
|
||||||
|
|
||||||
rootInfo = RootPtr( new EncFS_Root );
|
rootInfo = RootPtr( new EncFS_Root );
|
||||||
rootInfo->cipher = cipher;
|
rootInfo->cipher = cipher;
|
||||||
@ -1145,6 +1159,11 @@ void showFSInfo( const EncFSConfig &config )
|
|||||||
// xgroup(diag)
|
// xgroup(diag)
|
||||||
cout << _("File data IV is chained to filename IV.\n");
|
cout << _("File data IV is chained to filename IV.\n");
|
||||||
}
|
}
|
||||||
|
if(config.allowHoles)
|
||||||
|
{
|
||||||
|
// xgroup(diag)
|
||||||
|
cout << _("File holes passed through to ciphertext.\n");
|
||||||
|
}
|
||||||
cout << "\n";
|
cout << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,6 +58,7 @@ struct EncFSConfig
|
|||||||
bool externalIVChaining; // IV seeding by filename IV chaining
|
bool externalIVChaining; // IV seeding by filename IV chaining
|
||||||
|
|
||||||
bool chainedNameIV; // filename IV chaining
|
bool chainedNameIV; // filename IV chaining
|
||||||
|
bool allowHoles; // allow holes in files (implicit zero blocks)
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ConfigType
|
enum ConfigType
|
||||||
|
@ -30,6 +30,8 @@
|
|||||||
using namespace rlog;
|
using namespace rlog;
|
||||||
using namespace rel;
|
using namespace rel;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
using boost::shared_ptr;
|
||||||
|
using boost::dynamic_pointer_cast;
|
||||||
|
|
||||||
static RLogChannel *Info = DEF_CHANNEL("info/MACFileIO", Log_Info);
|
static RLogChannel *Info = DEF_CHANNEL("info/MACFileIO", Log_Info);
|
||||||
//
|
//
|
||||||
@ -157,6 +159,14 @@ off_t MACFileIO::getSize() const
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MACFileIO::allowHoles( bool allow )
|
||||||
|
{
|
||||||
|
BlockFileIO::allowHoles( allow );
|
||||||
|
shared_ptr<BlockFileIO> bf = dynamic_pointer_cast<BlockFileIO>( base );
|
||||||
|
if(bf)
|
||||||
|
bf->allowHoles( allow );
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t MACFileIO::readOneBlock( const IORequest &req ) const
|
ssize_t MACFileIO::readOneBlock( const IORequest &req ) const
|
||||||
{
|
{
|
||||||
int headerSize = macBytes + randBytes;
|
int headerSize = macBytes + randBytes;
|
||||||
@ -173,31 +183,49 @@ ssize_t MACFileIO::readOneBlock( const IORequest &req ) const
|
|||||||
// get the data from the base FileIO layer
|
// get the data from the base FileIO layer
|
||||||
ssize_t readSize = base->read( tmp );
|
ssize_t readSize = base->read( tmp );
|
||||||
|
|
||||||
|
// don't store zeros if configured for zero-block pass-through
|
||||||
|
bool skipBlock;
|
||||||
|
if( _allowHoles )
|
||||||
|
{
|
||||||
|
skipBlock = true;
|
||||||
|
for(int i=0; i<readSize; ++i)
|
||||||
|
if(tmp.data[i] != 0)
|
||||||
|
{
|
||||||
|
skipBlock = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
skipBlock = false;
|
||||||
|
|
||||||
if(readSize > headerSize)
|
if(readSize > headerSize)
|
||||||
{
|
{
|
||||||
// At this point the data has been decoded. So, compute the MAC of the
|
if(!skipBlock)
|
||||||
// block and check against the checksum stored in the header..
|
{
|
||||||
uint64_t mac = cipher->MAC_64( tmp.data + macBytes,
|
// At this point the data has been decoded. So, compute the MAC of
|
||||||
readSize - macBytes, key );
|
// the block and check against the checksum stored in the header..
|
||||||
|
uint64_t mac = cipher->MAC_64( tmp.data + macBytes,
|
||||||
|
readSize - macBytes, key );
|
||||||
|
|
||||||
for(int i=0; i<macBytes; ++i, mac >>= 8)
|
for(int i=0; i<macBytes; ++i, mac >>= 8)
|
||||||
{
|
{
|
||||||
int test = mac & 0xff;
|
int test = mac & 0xff;
|
||||||
int stored = tmp.data[i];
|
int stored = tmp.data[i];
|
||||||
if(test != stored)
|
if(test != stored)
|
||||||
{
|
{
|
||||||
// uh oh..
|
// uh oh..
|
||||||
long blockNum = req.offset / bs;
|
long blockNum = req.offset / bs;
|
||||||
rWarning(_("MAC comparison failure in block %li"),
|
rWarning(_("MAC comparison failure in block %li"),
|
||||||
blockNum);
|
blockNum);
|
||||||
if( !warnOnly )
|
if( !warnOnly )
|
||||||
{
|
{
|
||||||
MemoryPool::release( mb );
|
MemoryPool::release( mb );
|
||||||
throw ERROR(_("MAC comparison failure, refusing to read"));
|
throw ERROR(
|
||||||
}
|
_("MAC comparison failure, refusing to read"));
|
||||||
break;
|
}
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// now copy the data to the output buffer
|
// now copy the data to the output buffer
|
||||||
readSize -= headerSize;
|
readSize -= headerSize;
|
||||||
|
@ -53,6 +53,8 @@ public:
|
|||||||
|
|
||||||
virtual bool isWritable() const;
|
virtual bool isWritable() const;
|
||||||
|
|
||||||
|
virtual void allowHoles( bool allow );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual ssize_t readOneBlock( const IORequest &req ) const;
|
virtual ssize_t readOneBlock( const IORequest &req ) const;
|
||||||
virtual bool writeOneBlock( const IORequest &req );
|
virtual bool writeOneBlock( const IORequest &req );
|
||||||
|
Loading…
Reference in New Issue
Block a user