From 6d895fdc72ce02c3ff052431fd901ad64f98f317 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Mon, 17 Nov 2014 00:31:33 +0100 Subject: [PATCH] tests: Add --reverse file grow test This test uncovered issues caused by unsafe kernel-side and BlockFileIO caching. --- tests/common.inc | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/reverse.pl | 52 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 98 insertions(+), 8 deletions(-) diff --git a/tests/common.inc b/tests/common.inc index 1d597f7..ea3b93c 100644 --- a/tests/common.inc +++ b/tests/common.inc @@ -10,5 +10,59 @@ sub md5fh return $md5; } +# Get the file size from stat() (by file handle or name) +sub statSize +{ + my $f = shift; + my @s = stat($f) or die("stat on '$f' failed"); + return $s[7]; +} + +# Get the file size by read()ing the whole file +sub readSize +{ + my $fh = shift; + seek($fh, 0, 0); + my $s = read($fh, my $data, 10240); + $data = 0; + return $s; +} + +# Verify that the size of the file passed by filehandle matches the target size s0 +# Checks both stat() and read() +sub sizeVerify +{ + my $ok = 1; + my $fh = shift; + my $s0 = shift; + $ss = statSize($fh); + if ($s0 != $ss) { + $ok = 0; + print("# stat size $ss, expected $s0\n"); + } + $sr = readSize($fh); + if ($s0 != $sr) { + $ok = 0; + print("# read size $sr, expected $s0\n"); + } + return $ok; +} + +# Wait for a file to appear +use Time::HiRes qw(usleep); +sub waitForFile +{ + my $file = shift; + my $timeout; + $timeout = shift or $timeout = 5; + for(my $i = $timeout*10; $i > 0; $i--) + { + -f $file and return 1; + usleep(100000); # 0.1 seconds + } + print "# timeout waiting for '$file' to appear\n"; + return 0; +} + # As this file will be require()'d, it needs to return true return 1; diff --git a/tests/reverse.pl b/tests/reverse.pl index 821b2e5..3102fc8 100755 --- a/tests/reverse.pl +++ b/tests/reverse.pl @@ -2,9 +2,11 @@ # Test EncFS --reverse mode +use warnings; use Test::More qw( no_plan ); use File::Path; use File::Temp; +use IO::Handle; require("tests/common.inc"); @@ -31,7 +33,7 @@ sub cleanup { system("fusermount -u $decrypted"); system("fusermount -u $ciphertext"); - + our $workingDir; rmtree($workingDir); ok( ! -d $workingDir, "working dir removed"); } @@ -42,13 +44,12 @@ sub cleanup # Directory structure: plain -[encrypt]-> ciphertext -[decrypt]-> decrypted sub mount { - qx(./encfs/encfs --extpass="echo test" --standard $plain $ciphertext --reverse > /dev/null); - ok(-f "$plain/.encfs6.xml", "plain .encfs6.xml exists") or BAIL_OUT("'$plain/.encfs6.xml'"); - $e = encName(".encfs6.xml"); - ok(-f "$ciphertext/$e", "encrypted .encfs6.xml exists") or BAIL_OUT("'$ciphertext/$e'"); - - qx(ENCFS6_CONFIG=$plain/.encfs6.xml ./encfs/encfs --extpass="echo test" $ciphertext $decrypted); - ok(-f "$decrypted/.encfs6.xml", "decrypted .encfs6.xml exists") or BAIL_OUT("'$decrypted/.encfs6.xml'"); + system("./encfs/encfs --extpass=\"echo test\" --standard $plain $ciphertext --reverse"); + 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"); + ok(waitForFile("$decrypted/.encfs6.xml"), "decrypted .encfs6.xml exists") or BAIL_OUT("'$decrypted/.encfs6.xml'"); } # Helper function @@ -83,6 +84,40 @@ sub symlink_test unlink("$plain/symlink"); } +# Grow a file from 0 to x kB and +# * check the ciphertext length is correct (stat + read) +# * check that the decrypted length is correct (stat + read) +# * check that plaintext and decrypted are identical +sub grow { + # pfh ... plaintext file handle + open(my $pfh, ">", "$plain/grow"); + # vfh ... verification file handle + open(my $vfh, "<", "$plain/grow"); + $pfh->autoflush; + # ciphertext file name + my $cname = encName("grow"); + # cfh ... ciphertext file handle + ok(open(my $cfh, "<", "$ciphertext/$cname"), "open ciphertext grow file"); + # dfh ... decrypted file handle + ok(open(my $dfh, "<", "$decrypted/grow"), "open decrypted grow file"); + + # csz ... ciphertext size + ok(sizeVerify($cfh, 0), "ciphertext of empty file is empty"); + ok(sizeVerify($dfh, 0), "decrypted empty file is empty"); + + my $ok = 1; + for($i=1; $i < 20; $i++) + { + print($pfh "w") or die("write failed"); + # autoflush should make sure the write goes to the kernel + # immediately. Just to be sure, check it here. + sizeVerify($vfh, $i) or die("unexpected plain file size"); + sizeVerify($cfh, $i) or $ok = 0; + sizeVerify($dfh, $i) or $ok = 0; + } + ok($ok, "ciphertext and decrypted size of file grown to $i bytes"); +} + newWorkingDir(); mount(); @@ -91,5 +126,6 @@ symlink_test("/"); # absolute symlink_test("foo"); # relative symlink_test("/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/15/17/18"); # long symlink_test("!ยง\$%&/()\\<>#+="); # special characters +grow(); cleanup();