// Copyright (c) 2012-2014 Konstantin Isakov and ZBackup contributors, see CONTRIBUTORS // Part of ZBackup. Licensed under GNU GPLv2 or later + OpenSSL, see LICENSE #include #include "../../encrypted_file.hh" #include "../../encryption_key.hh" #include "../../random.hh" #include "../../tmp_mgr.hh" #include "../../check.hh" #include "../../adler32.hh" char rnd[ 16384 ]; Adler32::Value adler( int sz ) { Adler32 a; a.add( rnd, sz ); return a.result(); } void readAndWrite( EncryptionKey const & key, bool writeBackups, bool readBackups, bool readSkips ) { TmpMgr tmpMgr( "/dev/shm" ); sptr< TemporaryFile > tempFile = tmpMgr.makeTemporaryFile(); int fileSize = rand() % ( sizeof( rnd ) + 1 ); fprintf( stderr, "Run with %d bytes, %s%s%s%sfile %s...\n", fileSize, key.hasKey() ? "" : "no encryption, ", writeBackups ? "write backups, " : "", readBackups ? "read backups, " : "", readSkips ? "read skips, " : "", tempFile->getFileName().c_str() ); char iv[ Encryption::IvSize ]; Random::genaratePseudo( iv, sizeof( iv ) ); // Write { EncryptedFile::OutputStream out( tempFile->getFileName().c_str(), key, iv ); char const * next = rnd; int avail = 0; for ( int left = fileSize; left; ) { CHECK( out.ByteCount() == fileSize - left, "Incorrect bytecount in the " "middle of writing" ); void * data; CHECK( out.Next( &data, &avail ), "out.Next() returned false" ); CHECK( avail > 0, "out.Next() returned zero size" ); bool doBackup = writeBackups && ( rand() & 1 ); int backup; if ( doBackup ) { backup = rand() % ( avail + 1 ); // Make sure we don't back up and then need to back up again to finish // the write if ( avail > left ) backup = avail - left; avail -= backup; } int toWrite = avail > left ? left : avail; memcpy( data, next, toWrite ); if ( doBackup ) out.BackUp( backup ); next += toWrite; left -= toWrite; avail -= toWrite; if ( !avail && ( rand() & 1 ) ) { CHECK( adler( next - rnd ) == out.getAdler32(), "bad adler32 in the middle of writing" ); } } if ( avail || ( rand() & 1 ) ) out.BackUp( avail ); CHECK( out.ByteCount() == fileSize, "Incorrect bytecount after writing" ); if ( rand() & 1 ) { CHECK( adler( fileSize ) == out.getAdler32(), "bad adler32 of the written file" ); } } // Read back { EncryptedFile::InputStream in( tempFile->getFileName().c_str(), key, iv ); char const * next = rnd; void const * data; int avail = 0; for ( int left = fileSize; left; ) { if ( readSkips && ( rand() & 1 ) ) { int toSkip = rand() % ( left + 1 ); in.Skip( toSkip ); next += toSkip; left -= toSkip; avail = 0; continue; } CHECK( in.ByteCount() == fileSize - left, "Incorrect bytecount in the " "middle of reading" ); CHECK( in.Next( &data, &avail ), "file ended while %d were still left", left ); CHECK( avail > 0, "in.Next() returned zero size" ); bool doBackup = readBackups && ( rand() & 1 ); int backup; if ( doBackup ) { backup = rand() % ( avail + 1 ); avail -= backup; } int toRead = avail > left ? left : avail; CHECK( memcmp( next, data, toRead ) == 0, "Different bytes read than " "expected at offset %d", int( next - rnd ) ); if ( doBackup ) in.BackUp( backup ); next += toRead; left -= toRead; avail -= toRead; if ( !avail && ( rand() & 1 ) ) { CHECK( adler( next - rnd ) == in.getAdler32(), "bad adler32 in the middle of the reading" ); } } CHECK( in.ByteCount() == fileSize, "Incorrect bytecount after reading" ); CHECK( !avail, "at least %d bytes still available", avail ); CHECK( !in.Next( &data, &avail ), "file should have ended but resulted in " "%d more bytes", avail ); if ( rand() & 1 ) { CHECK( adler( fileSize ) == in.getAdler32(), "bad adler32 of the read file" ); } } } int main() { Random::genaratePseudo( rnd, sizeof( rnd ) ); EncryptionKeyInfo keyInfo; EncryptionKey::generate( "blah", keyInfo ); EncryptionKey key( "blah", &keyInfo ); EncryptionKey noKey( std::string(), NULL ); for ( size_t iteration = 100000; iteration--; ) readAndWrite( ( rand() & 1 ) ? key : noKey, rand() & 1, rand() & 1, rand() & 1 ); }