"Fossies" - the Fresh Open Source Software Archive 
Member "encfs-1.9.5/integration/normal.t.pl" (27 Apr 2018, 13894 Bytes) of package /linux/misc/encfs-1.9.5.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Perl source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
See also the latest
Fossies "Diffs" side-by-side code changes report for "normal.t.pl":
1.9.4_vs_1.9.5.
1 #!/usr/bin/perl -w
2
3 # Test EncFS normal and paranoid mode
4
5 use Test::More tests => 136;
6 use File::Path;
7 use File::Copy;
8 use File::Temp;
9 use IO::Handle;
10
11 require("integration/common.pl");
12
13 my $tempDir = $ENV{'TMPDIR'} || "/tmp";
14
15 if($^O eq "linux" and $tempDir eq "/tmp") {
16 # On Linux, /tmp is often a tmpfs mount that does not support
17 # extended attributes. Use /var/tmp instead.
18 $tempDir = "/var/tmp";
19 }
20
21 # Find attr binary
22 # Linux
23 my $setattr = "attr -s encfs -V hello";
24 my $getattr = "attr -g encfs";
25 if(system("which xattr > /dev/null 2>&1") == 0)
26 {
27 # Mac OS X
28 $setattr = "xattr -sw encfs hello";
29 $getattr = "xattr -sp encfs";
30 }
31 if(system("which lsextattr > /dev/null 2>&1") == 0)
32 {
33 # FreeBSD
34 $setattr = "setextattr -h user encfs hello";
35 $getattr = "getextattr -h user encfs";
36 }
37
38 # Do we support xattr ?
39 my $have_xattr = 1;
40 if(system("./build/encfs --verbose --version 2>&1 | grep -q HAVE_XATTR") != 0)
41 {
42 $have_xattr = 0;
43 }
44
45 # Did we ask, or are we simply able to run "sudo" tests ?
46 my $sudo_cmd;
47 if ($> == 0)
48 {
49 $sudo_cmd="";
50 }
51 elsif (defined($ENV{'SUDO_TESTS'}))
52 {
53 $sudo_cmd="sudo";
54 }
55
56 # test filesystem in standard config mode
57 &runTests('standard');
58
59 # test in paranoia mode
60 &runTests('paranoia');
61
62 # Wrapper function - runs all tests in the specified mode
63 sub runTests
64 {
65 my $mode = shift;
66 print STDERR "\nrunTests: mode=$mode sudo=";
67 print STDERR (defined($sudo_cmd) ? "on" : "off")."\n";
68
69 &newWorkingDir;
70
71 my $hardlinks = 1;
72 if($mode eq 'standard')
73 {
74 &mount("--standard");
75 } elsif($mode eq 'paranoia')
76 {
77 &mount("--paranoia");
78 $hardlinks = 0; # no hardlinks in paranoia mode
79 &corruption;
80 } else
81 {
82 die "invalid test mode";
83 }
84
85 # tests..
86 &fileCreation;
87 &links($hardlinks);
88 &truncate;
89 &renames;
90 &internalModification;
91 &grow;
92 &umask0777;
93 &create_unmount_remount;
94 &checkReadError;
95 &checkWriteError;
96
97 &configFromPipe;
98 &cleanup;
99 }
100
101 # Helper function
102 # Create a new empty working directory
103 sub newWorkingDir
104 {
105 our $workingDir = mkdtemp("$tempDir/encfs-tests-XXXX")
106 || BAIL_OUT("Could not create temporary directory");
107
108 our $raw = "$workingDir/raw";
109 our $crypt = "$workingDir/crypt";
110 if ($^O eq "cygwin")
111 {
112 $crypt = "/cygdrive/x";
113 }
114 }
115
116 # Test Corruption
117 # Modify the encrypted file and verify that the MAC check detects it
118 sub corruption
119 {
120 ok( open(OUT, "+> $crypt/corrupt") && print(OUT "12345678901234567890")
121 && close(OUT), "create corruption-test file" );
122
123
124 $e = encName("corrupt");
125 ok( open(OUT, ">> $raw/$e") && print(OUT "garbage") && close(OUT),
126 "corrupting raw file");
127
128 ok( open(IN, "< $crypt/corrupt"), "open corrupted file");
129 my $content;
130 $result = read(IN, $content, 20);
131 # Cygwin returns EINVAL for now
132 ok(($!{EBADMSG} || $!{EINVAL}) && (! defined $result), "corrupted file with MAC returns read error: $!");
133 }
134
135 # Test internal modification
136 # Create a file of fixed size and overwrite data at different offsets
137 # (like a database would do)
138 sub internalModification
139 {
140 $ofile = "$workingDir/crypt-internal-$$";
141 writeZeroes($ofile, 2*1024);
142 ok(copy($ofile, "$crypt/internal"), "copying crypt-internal file");
143
144 open(my $out1, "+<", "$crypt/internal");
145 open(my $out2, "+<", $ofile);
146
147 @fhs = ($out1, $out2);
148
149 $ori = md5fh($out1);
150 $b = md5fh($out2);
151
152 ok( $ori eq $b, "random file md5 matches");
153
154 my @offsets = (10, 30, 1020, 1200);
155 foreach my $o (@offsets)
156 {
157 foreach my $fh(@fhs) {
158 seek($fh, $o, 0);
159 print($fh "garbagegarbagegarbagegarbagegarbage");
160 }
161 $a=md5fh($out1);
162 $b=md5fh($out2);
163 ok( ($a eq $b) && ($a ne $ori), "internal modification at $o");
164 }
165
166 close($out1);
167 close($out2);
168 }
169
170 # Test renames
171 sub renames
172 {
173 ok( open(F, ">$crypt/orig-name") && close F, "create file for rename test");
174 ok( -f "$crypt/orig-name", "file exists");
175
176 ok( rename("$crypt/orig-name", "$crypt/2nd-name"), "rename");
177 ok( ! -f "$crypt/orig-name", "file exists");
178 ok( -f "$crypt/2nd-name", "file exists");
179
180 # rename directory with contents
181 ok( mkpath("$crypt/orig-dir/foo"), "mkdir for rename test");
182 ok( open(F, ">$crypt/orig-dir/foo/bar") && close F, "make file");
183
184 ok( rename("$crypt/orig-dir", "$crypt/new-dir"), "rename dir");
185 ok( -f "$crypt/new-dir/foo/bar", "dir rename contents");
186
187 # TODO: rename failure? (check undo works)
188
189 # check time stamps of files on rename
190 my $mtime = (stat "$crypt/2nd-name")[9];
191 # change time to 60 seconds earlier
192 my $olderTime = $mtime - 60;
193 ok( utime($olderTime, $olderTime, "$crypt/2nd-name"), "change time");
194
195 ok( rename("$crypt/2nd-name", "$crypt/3rd-name"), "rename");
196 is( (stat "$crypt/3rd-name")[9], $olderTime, "time unchanged by rename");
197 }
198
199 # Test truncate and grow
200 sub truncate
201 {
202 # write to file, then truncate it
203 ok( open(OUT, "+> $crypt/trunc"), "create truncate-test file");
204 autoflush OUT 1;
205 print OUT "12345678901234567890";
206
207 is( -s "$crypt/trunc", 20, "initial file size" );
208
209 ok( truncate(OUT, 10), "truncate" );
210
211 is( -s "$crypt/trunc", 10, "truncated file size");
212 is( qx(cat "$crypt/trunc"), "1234567890", "truncated file contents");
213
214 # try growing the file as well.
215 ok( truncate(OUT, 30), "truncate extend");
216 is( -s "$crypt/trunc", 30, "truncated file size");
217
218 seek(OUT, 30, 0);
219 print OUT "12345";
220 is( -s "$crypt/trunc", 35, "truncated file size");
221
222 is( md5fh(*OUT), "5f170cc34b1944d75d86cc01496292df",
223 "content digest");
224
225 # try crossing block boundaries
226 seek(OUT, 10000,0);
227 print OUT "abcde";
228
229 is( md5fh(*OUT), "117a51c980b64dcd21df097d02206f98",
230 "content digest");
231
232 # then truncate back to 35 chars
233 truncate(OUT, 35);
234 is( md5fh(*OUT), "5f170cc34b1944d75d86cc01496292df",
235 "content digest");
236
237 close OUT;
238 }
239
240 # Test file creation and removal
241 sub fileCreation
242 {
243 # first be sure .encfs6.xml does not show up
244 my $f = encName(".encfs6.xml");
245 cmp_ok( length($f), '>', 8, "encrypted name ok" );
246 ok( ! -f "$raw/$f", "configuration file .encfs6.xml not visible in $raw" );
247
248 # create a file
249 qx(date > "$crypt/df.txt");
250 ok( -f "$crypt/df.txt", "file created" ) || BAIL_OUT("file create failed");
251
252 # ensure there is an encrypted version.
253 my $c = encName("df.txt");
254 cmp_ok( length($c), '>', 8, "encrypted name ok" );
255 ok( -f "$raw/$c", "encrypted file $raw/$c created" );
256
257 # check contents
258 my $count = qx(grep -c crypt-$$ "$crypt/df.txt");
259 isnt(scalar($count), 0, "encrypted file readable");
260
261 unlink "$crypt/df.txt";
262 ok( ! -f "$crypt/df.txt", "file removal" );
263 ok( ! -f "$raw/$c", "file removal" );
264 }
265
266 # Test file growth
267 sub grow
268 {
269 open(my $fh_a, "+>$crypt/grow");
270 open(my $fh_b, "+>$workingDir/grow");
271
272 my $d = "1234567"; # Length 7 so we are not aligned to the block size
273 my $len = 7;
274
275 my $old = "";
276 my $errs = 0;
277
278 my $i;
279 for($i=1; $i<1000; $i++)
280 {
281 print($fh_a $d);
282 print($fh_b $d);
283
284 my $a = md5fh($fh_a);
285 my $b = md5fh($fh_b);
286
287 my $size = $len * $i;
288
289 # md5sums must be identical but must have changed
290 if($a ne $b || $a eq $old)
291 {
292 $errs++;
293 }
294
295 $old = $a;
296 }
297
298 ok($errs == 0, "grow file by $len bytes, $i times");
299
300 close($fh_a);
301 close($fh_b);
302 }
303
304 # Helper function
305 # Check a file's content
306 sub checkContents
307 {
308 my ($file, $expected, $testName) = @_;
309
310 open(IN, "< $file");
311 my $line = <IN>;
312 is( $line, $expected, $testName );
313
314 close IN;
315 }
316
317 # Helper function
318 # Convert plain-text filename to encrypted filename
319 sub encName
320 {
321 my $plain = shift;
322 my $enc = qx(./build/encfsctl encode --extpass="echo test" $raw $plain);
323 chomp($enc);
324 return $enc;
325 }
326
327 # Test symlinks & hardlinks, and extended attributes
328 sub links
329 {
330 my $hardlinkTests = shift;
331
332 my $contents = "hello world";
333 ok( open(OUT, "> $crypt/data"), "create file for link test" );
334 print OUT $contents;
335 close OUT;
336
337 # symlinks
338 ok( symlink("$crypt/data", "$crypt/data-fqn") , "fqn symlink");
339 checkContents("$crypt/data-fqn", $contents, "fqn link traversal");
340 is( readlink("$crypt/data-fqn"), "$crypt/data", "read fqn symlink");
341
342 ok( symlink("data", "$crypt/data-rel"), "local symlink");
343 checkContents("$crypt/data-rel", $contents, "rel link traversal");
344 is( readlink("$crypt/data-rel"), "data", "read rel symlink");
345
346 SKIP: {
347 skip "No hardlink support", 2 unless $hardlinkTests;
348
349 ok( link("$crypt/data", "$crypt/data.2"), "hard link");
350 checkContents("$crypt/data.2", $contents, "hardlink read");
351 };
352
353 # extended attributes
354 my $return_code = ($have_xattr) ? system("$setattr $crypt/data") : 0;
355 is($return_code, 0, "extended attributes can be set (return code was $return_code)");
356 $return_code = ($have_xattr) ? system("$getattr $crypt/data") : 0;
357 is($return_code, 0, "extended attributes can be get (return code was $return_code)");
358 # this is suppused to fail, so get rid of the error message
359 $return_code = ($have_xattr) ? system("$getattr $crypt/data-rel 2> /dev/null") : 1;
360 isnt($return_code, 0, "extended attributes operations do not follow symlinks (return code was $return_code)");
361 }
362
363 # Test mount
364 # Leaves the filesystem mounted - also used as a helper function
365 sub mount
366 {
367 my $args = shift;
368
369 # When these fail, the rest of the tests makes no sense
370 mkdir($raw) || BAIL_OUT("Could not create $raw: $!");
371 if ($^O ne "cygwin")
372 {
373 mkdir($crypt) || BAIL_OUT("Could not create $crypt: $!");
374 }
375
376 delete $ENV{"ENCFS6_CONFIG"};
377 remount($args);
378 ok( $? == 0, "encfs command returns 0") || BAIL_OUT("");
379 ok( -f "$raw/.encfs6.xml", "created control file") || BAIL_OUT("");
380 }
381
382 # Helper function
383 # Mount without any prior checks
384 sub remount
385 {
386 my $args = shift;
387 my $cmdline = "./build/encfs --extpass=\"echo test\" $args $raw $crypt 2>&1";
388 # This makes sure we get to see stderr ^
389 system($cmdline);
390 }
391
392 # Helper function
393 # Unmount and delete mountpoint
394 sub cleanup
395 {
396 portable_unmount($crypt);
397
398 rmdir $crypt;
399 ok( ! -d $crypt, "unmount ok, mount point removed");
400
401 rmtree($workingDir);
402 ok( ! -d $workingDir, "working dir removed");
403 }
404
405 # Test that we can create and write to a a file even if umask is set to 0777
406 # Regression test for bug https://github.com/vgough/encfs/issues/181
407 sub umask0777
408 {
409 my $old = umask(0777);
410 ok(open(my $fh, "+>$crypt/umask0777"), "open with umask 0777");
411 close($fh);
412 umask($old);
413 }
414
415 # Test that we can read the configuration from a named pipe
416 # Regression test for https://github.com/vgough/encfs/issues/253
417 sub configFromPipe
418 {
419 portable_unmount($crypt);
420 rename("$raw/.encfs6.xml", "$raw/.encfs6.xml.orig");
421 system("mkfifo $raw/.encfs6.xml");
422 my $child = fork();
423 unless ($child) {
424 &remount("--standard");
425 exit;
426 }
427 system("cat $raw/.encfs6.xml.orig > $raw/.encfs6.xml");
428 waitpid($child, 0);
429 ok( 0 == $?, "encfs mount with named pipe based config failed");
430 }
431
432 sub create_unmount_remount
433 {
434 my $crypt = "$workingDir/create_remount.crypt";
435 my $mnt = "$workingDir/create_remount.mnt";
436 if ($^O eq "cygwin")
437 {
438 $mnt = "/cygdrive/y";
439 }
440 mkdir($crypt) || BAIL_OUT($!);
441 if ($^O ne "cygwin")
442 {
443 mkdir($mnt) || BAIL_OUT($!);
444 }
445
446 system("./build/encfs --standard --extpass=\"echo test\" $crypt $mnt 2>&1");
447 ok( $? == 0, "encfs command returns 0") || return;
448 ok( -f "$crypt/.encfs6.xml", "created control file") || return;
449
450 # Write some text
451 my $contents = "hello world\n";
452 ok( open(OUT, "> $mnt/test_file_1"), "write content");
453 print OUT $contents;
454 close OUT;
455
456 # Unmount
457 portable_unmount($mnt);
458
459 # Mount again, testing -c at the same time
460 rename("$crypt/.encfs6.xml", "$crypt/.encfs6_moved.xml");
461 system("./build/encfs -c $crypt/.encfs6_moved.xml --extpass=\"echo test\" $crypt $mnt 2>&1");
462 ok( $? == 0, "encfs command returns 0") || return;
463
464 # Check if content is still there
465 checkContents("$mnt/test_file_1", $contents);
466
467 portable_unmount($mnt);
468 }
469
470 # Test that read errors are correctly thrown up to us
471 sub checkReadError
472 {
473 # Not sure how to implement this, so feel free !
474 ok(1, "read error");
475 }
476
477 # Test that write errors are correctly thrown up to us
478 sub checkWriteError
479 {
480 # No OSX impl (for now, feel free to find how to), and requires "sudo".
481 if($^O eq "darwin" || !defined($sudo_cmd)) {
482 ok(1, "write error");
483 ok(1, "write error");
484 ok(1, "write error");
485 ok(1, "write error");
486 }
487 else {
488 my $crypt = "$workingDir/checkWriteError.crypt";
489 my $mnt = "$workingDir/checkWriteError.mnt";
490 if ($^O eq "cygwin")
491 {
492 $mnt = "/cygdrive/z";
493 }
494 mkdir($crypt) || BAIL_OUT($!);
495 if ($^O ne "cygwin")
496 {
497 mkdir($mnt) || BAIL_OUT($!);
498 }
499 system("$sudo_cmd mount -t tmpfs -o size=1m tmpfs $crypt");
500 ok( $? == 0, "mount command returns 0") || return;
501 system("./build/encfs --standard --extpass=\"echo test\" $crypt $mnt 2>&1");
502 ok( $? == 0, "encfs command returns 0") || return;
503 ok(open(OUT , "> $mnt/file"), "write content");
504 while(print OUT "0123456789") {}
505 ok ($!{ENOSPC}, "write returned $! instead of ENOSPC");
506 close OUT;
507 portable_unmount($mnt);
508 system("$sudo_cmd umount $crypt");
509 }
510 }