Archive::Zip - _isSeekable a bit bodgy

M

Matthew Braid

Hi all,

I've just found a rather annoying problem with Archive::Zip.

I'm using temp files (via File::Temp's tempfile function) to store
zipped data from a database. Unfortunately it seems there was a change
in the last version that makes Archive::Zip want a seekable handle for
the readFromFileHandle, and Archive::Zip doesn't want to believe that
temp files are seekable.

I checked the _isSeekable function in Archive::Zip:

sub _isSeekable # Archive::Zip
{
my $fh = shift;

if ( UNIVERSAL::isa( $fh, 'IO::Scalar' ) )
{
return 0;
}
elsif ( UNIVERSAL::isa( $fh, 'IO::String' ) )
{
return 1;
}
elsif ( UNIVERSAL::can( $fh, 'stat' ) )
{
return -f $fh;
}
return UNIVERSAL::can( $fh, 'seek' );
}

The problem is that the -f $fh is wrapped in a UNIVERSAL::can(). I've
never had much luck with UNIVERSAL::can(), and sure enough it's failing
here. A quick demo shows this:

use File::Temp qw/tempfile/;
my $fh = tempfile(UNLINK => 1);
print "Can stat? ", (UNIVERSAL::can($fh, 'stat') ? 1 : 0), "\n";
print "Is file? ", (-f $fh ? 1 : 0), "\n";

Can stat? 0
Is file? 1

A better way to do this test would be to use eval. Instead of:

elsif ( UNIVERSAL::can( $fh, 'stat' ) )
{
return -f $fh;
}

use:

return 1 if eval {-f $fh};

BTW, has anyone reliably used UNIVERSAL::can? It never seems to work for
me...

MB
 
A

Anno Siegel

Matthew Braid said:
Hi all,

I've just found a rather annoying problem with Archive::Zip.

I'm using temp files (via File::Temp's tempfile function) to store
zipped data from a database. Unfortunately it seems there was a change
in the last version that makes Archive::Zip want a seekable handle for
the readFromFileHandle, and Archive::Zip doesn't want to believe that
temp files are seekable.

I checked the _isSeekable function in Archive::Zip:

sub _isSeekable # Archive::Zip
{
my $fh = shift;

if ( UNIVERSAL::isa( $fh, 'IO::Scalar' ) )
{
return 0;
}
elsif ( UNIVERSAL::isa( $fh, 'IO::String' ) )
{
return 1;
}
elsif ( UNIVERSAL::can( $fh, 'stat' ) )
{
return -f $fh;
}
return UNIVERSAL::can( $fh, 'seek' );
}

The problem is that the -f $fh is wrapped in a UNIVERSAL::can(). I've
never had much luck with UNIVERSAL::can(), and sure enough it's failing
here. A quick demo shows this:

It is true that ->can has problems (in particular in combination with
AUTOLOAD), but in this case it's right. tempfile() returns an unblessed
globref, which indeed doesn't have a ->stat method. That the Perl function
stat() knows how to deal with it is outside ->can's responsibility.

The bug is in Archive::Zip. It should probably add a test "ref( $fh) eq
'GLOB'" in _is_seekable to catch this.

For a quick fix try blessing the temp fh into IO::File before using it.
That should repair the behavior of Archive::Zip without hurting the file
handle as such. Untested.

Anno
 
M

Matthew Braid

Anno said:
It is true that ->can has problems (in particular in combination with
AUTOLOAD), but in this case it's right. tempfile() returns an unblessed
globref, which indeed doesn't have a ->stat method. That the Perl function
stat() knows how to deal with it is outside ->can's responsibility.

I humbly apologise to UNIVERSAL and its ->can :)
The bug is in Archive::Zip. It should probably add a test "ref( $fh) eq
'GLOB'" in _is_seekable to catch this.

I find it a little odd that it checks at all - the doco says the input
file handle must be seekable, so assuming it is and letting the seek die
would have been the appropriate thing to do IMHO.
For a quick fix try blessing the temp fh into IO::File before using it.
That should repair the behavior of Archive::Zip without hurting the file
handle as such. Untested.

This seems to work. It may screw up some kind of filehandle arcanum, but
I'm only doing simple reads/writes/seeks so it should be OK. Ta :)

MB
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,825
Latest member
VernonQuy6

Latest Threads

Top