Closed halostatue closed 9 years ago
From a02b9155192e6812042c016d8498c1c4730b81f7 Mon Sep 17 00:00:00 2001 Date: Sun, 13 Apr 2008 19:23:28 +0200 Subject: [PATCH] Fix minitar when working with non-seekable streams.
The use of duck typing was not sufficient for pipes and files created by popen, because the relevant methods exist but throw errors. Explicitly check for a regular file before calling seek-related methods.
We still support duck typing for streams that don't descend from ruby's IO, but I haven't been able to find a use or a test for that.
Hello, here is a small bug fix for minitar. Thanks for this useful library!
minitar.rb | 30 +++++++++++++++++++++++------- 1 files changed, 23 insertions(+), 7 deletions(-)
diff --git a/minitar.rb b/minitar.rb
index 29336e0..2f14027 100644
--- a/minitar.rb
+++ b/minitar.rb
@@ -366,7 +366,7 @@ module Archive::Tar::Minitar
def add_file(name, opts = {}) # :yields RestrictedStream, +opts+:
raise Archive::Tar::Minitar::BlockRequired unless block_given?
raise Archive::Tar::Minitar::ClosedStream if @closed
- raise Archive::Tar::Minitar::NonSeekableStream unless @io.respond_to?(:pos=)
+ raise Archive::Tar::Minitar::NonSeekableStream unless Archive::Tar::Minitar::can_seek(@io)
name, prefix = split_name(name)
init_pos = @io.pos
@@ -480,7 +480,7 @@ module Archive::Tar::Minitar
@devminor = header.devminor
@prefix = header.prefix
@read = 0
- @orig_pos = @io.pos
+ @orig_pos = @io.pos if Archive::Tar::Minitar::can_seek(@io)
end
# Reads +len+ bytes (or all remaining data) from the entry. Returns
@@ -528,7 +528,7 @@ module Archive::Tar::Minitar
# Sets the current read pointer to the beginning of the EntryStream.
def rewind
- raise NonSeekableStream unless @io.respond_to?(:pos=)
+ raise NonSeekableStream unless Archive::Tar::Minitar::can_seek(@io)
@io.pos = @orig_pos
@read = 0
end
@@ -579,7 +579,7 @@ module Archive::Tar::Minitar
# Creates and returns a new Reader object.
def initialize(anIO)
@io = anIO
- @init_pos = anIO.pos
+ @init_pos = anIO.pos if Archive::Tar::Minitar::can_seek(anIO)
end
# Iterates through each entry in the data stream.
@@ -592,10 +592,10 @@ module Archive::Tar::Minitar
# random access data streams that respond to #rewind and #pos.
def rewind
if @init_pos == 0
- raise NonSeekableStream unless @io.respond_to?(:rewind)
+ raise NonSeekableStream unless Archive::Tar::Minitar::can_seek(@io)
@io.rewind
else
- raise NonSeekableStream unless @io.respond_to?(:pos=)
+ raise NonSeekableStream unless Archive::Tar::Minitar::can_seek(@io)
@io.pos = @init_pos
end
end
@@ -615,7 +615,7 @@ module Archive::Tar::Minitar
skip = (512 - (size % 512)) % 512
- if @io.respond_to?(:seek)
+ if Archive::Tar::Minitar::can_seek(@io)
# avoid reading...
@io.seek(size - entry.bytes_read, IO::SEEK_CUR)
else
@@ -827,6 +827,19 @@ module Archive::Tar::Minitar
end
class << self
+ # Check whether +io+ will be able to seek without errors
+ def can_seek(io)
+ # The IO class will throw at runtime if we call
+ # seek/rewind/pos/pos=
+ # on a non-regular file.
+ if io.respond_to?(:stat) then
+ return io.stat.file?
+ end
+
+ # Support duck typing - don't know any users though
+ return [:pos, :pos=, :seek, :rewind ] .all? { |m| io.respond_to?(m) }
+ end
+
# Tests if +path+ refers to a directory. Fixes an apparently
# corrupted <tt>stat()</tt> call on Windows.
def dir?(path)
@@ -977,3 +990,6 @@ module Archive::Tar::Minitar
end
end
end
+
+
+
Gabriel
Date: 2005-10-01 08:0 Submitted By: Michal Suchanek (http://rubyforge.org/users/hramrach)
Detailed description ruby 1.8.2 (2004-07-29) [powerpc-darwin]
I found that minitar relies on respond_to to determine an IO is seekable. This does not work for me as STDIN does respond to seek, pos, and pos= but they raise an exception when called.
I am posting a patch that makes it work for listing. I can list a package content with "dpkg-deb --fsys-tarfile popt* | ruby bin/minitar list --verbose -" but it staill raises an exception after the listing is printed.
The patch is untested for any other uses and does not solve the problem for readonly/writeonly streams where the same detection is used.