-
Notifications
You must be signed in to change notification settings - Fork 16
Description
I have a small reproducer demonstrating that IO::Uncompress::Unzip's file descriptor won't work with Storable. Presumably there are other cases...
If I had to guess, it would be that the FH, which is passed to Storable's XS code, may not be positioned (for XS) correctly after header detection...Clearly, it works for ordinary Perl consumers.
Here is the sequence:
- Write a small hash to a file with Storable.
- Using system zip, create a zip file containing the Storable file.
- Read the Storable file from
\*STDIN
& verify that it's what we wrote. (passes) - Read the Storable file from *STDIN with IUU, passing the file handle to Storable (fails)
- Read the zip archive of the Storable file from *STDIN with IUU, passing file handle to Storable (fails)
- Delete the file, extract it from the Zip archive, and read it from *STDIN with Storable (passes
From this, we can see that the file is written correctly by Storable, and can be read after a trip thru the Zip archive. Further, Storable is happy reading from a file handle.
BUT, neither the raw file nor the Zip member can be read correctly by Storable if IUU is in the middle.
IO::Uncompress::Unzip 2.102
In real life, the work-around is to write all 300MB of uncompressed data to a tempfile, and pass that handle to Storable. Which is suboptimal...
Here is the test program:
#!/usr/bin/perl
use warnings;
use strict;
use Storable( qw/store fd_retrieve/ );
use IO::Uncompress::Unzip;
exit unless( @ARGV);
my $cmd = shift;
if( $cmd eq "write" ) {
my $file = shift or die( "no file\n" );
my $hash = { key => 'value' };
store( $hash, $file );
system( "zip $file.zip $file" );
exit;
}
if( $cmd eq "storable" ) {
binmode( \*STDIN );
my $read = fd_retrieve( \*STDIN );
if( !$read || !exists $read->{key} ){
print "Failed\n";
} else {
print "OK\n";
}
exit;
}
if( $cmd eq 'uncompress' ) {
my $in = IO::Uncompress::Unzip->new( \*STDIN, { } ) or die( "IUU\n" );
binmode( $in );
my $read = fd_retrieve( $in );
if( !$read || !exists $read->{key} ){
print "Failed\n";
} else {
print "OK\n";
}
exit;
}
if( $cmd eq 'extract' ) {
my $file = shift or die( "no file" );
system( "rm $file; unzip $file.zip;" );
system( "$0 storable <$file" );
exit;
}
die( "Bad command $cmd\n" );
exit;
And here are the commands (Yes, it fails with newer versions of Perl, and yes in real life there's error checking):
# ./IUZ-Storable.pl write foo # Write hash to file "foo" and zip
adding: foo (stored 0%)
# ./IUZ-Storable.pl storable <foo # Read with Storable and verify
OK
# ./IUZ-Storable.pl uncompress <foo # Read foo (transparent mode) via IUU fails
Magic number checking on storable string failed at /usr/lib/perl5/5.8.8/i386-linux-thread-multi/Storable.pm line 443, at ./IUZ-Storable.pl line 38.
# ./IUZ-Storable.pl uncompress <foo.zip # Read Zip archive via IUU fails
Magic number checking on storable string failed at /usr/lib/perl5/5.8.8/i386-linux-thread-multi/Storable.pm line 443, at ./IUZ-Storable.pl line 38.
# ./IUZ-Storable.pl extract foo # Extract from zip file and read/verify with Storable
Archive: foo.zip
extracting: foo
OK
#
FWIW, strace doesn't show anything odd on the system side of the pipe.
strace -f ./IUZ-Storable.pl uncompress <foo
(...)
read(0, "pst0\4\t\0041234\4\4\4\10\3\1\0\0\0\n\5value\3\0\0\0k"..., 4096) = 34
write(2, "Magic number checking on storabl"..., 148Magic number checking on storable string failed at /usr/lib/perl5/5.8.8/i386-linu (...)
# And here's the entire Storable file (34 bytes);
## od -tao1 foo
0000000 p s t 0 eot ht eot 1 2 3 4 eot eot eot bs etx
160 163 164 060 004 011 004 061 062 063 064 004 004 004 010 003
0000020 soh nul nul nul nl enq v a l u e etx nul nul nul k
001 000 000 000 012 005 166 141 154 165 145 003 000 000 000 153
0000040 e y
145 171
0000042