halostatue / minitar

Minimal pure-ruby support for POSIX tar(1) archives.
Other
38 stars 27 forks source link

minitar does not work on stdin #2

Closed halostatue closed 9 years ago

halostatue commented 13 years ago

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.


Only in archive-tar-minitar-0.5.1: archive
diff -ur archive-tar-minitar-0.5.1.org/lib/archive/tar/minitar.rb archive-tar-minitar-0.5.1/lib/archive/tar/minitar.rb
--- archive-tar-minitar-0.5.1.org/lib/archive/tar/minitar.rb    Wed Sep 22 19:47:43 2004
+++ archive-tar-minitar-0.5.1/lib/archive/tar/minitar.rb    Sat Oct  1 13:30:48 2005
@@ -366,10 +366,10 @@
     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=)
+      init_pos = @io.pos rescue nil
+      raise Archive::Tar::Minitar::NonSeekableStream unless init_pos

       name, prefix = split_name(name)
-      init_pos = @io.pos
       @io.write("\0" * 512) # placeholder for the header

       yield RestrictedStream.new(@io), opts
@@ -480,7 +480,7 @@
         @devminor = header.devminor
         @prefix   = header.prefix
         @read     = 0
-        @orig_pos = @io.pos
+        @orig_pos = @io.pos rescue nil
       end

         # Reads +len+ bytes (or all remaining data) from the entry. Returns
@@ -528,7 +528,7 @@

         # Sets the current read pointer to the beginning of the EntryStream.
       def rewind
-        raise NonSeekableStream unless @io.respond_to?(:pos=)
+        raise NonSeekableStream unless @orig_pos
         @io.pos = @orig_pos
         @read = 0
       end
@@ -579,7 +579,7 @@
       # Creates and returns a new Reader object.
     def initialize(anIO)
       @io     = anIO
-      @init_pos = anIO.pos
+      @init_pos = anIO.pos rescue nil
     end

       # Iterates through each entry in the data stream.
@@ -592,10 +592,10 @@
       # 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 @init_pos
         @io.rewind
       else
-        raise NonSeekableStream unless @io.respond_to?(:pos=)
+        raise NonSeekableStream unless @init_pos
         @io.pos = @init_pos
       end
     end
@@ -615,7 +615,7 @@

         skip = (512 - (size % 512)) % 512

-        if @io.respond_to?(:seek)
+        if @init_pos #@io.respond_to?(:seek)
             # avoid reading...
           @io.seek(size - entry.bytes_read, IO::SEEK_CUR)
         else
Only in archive-tar-minitar-0.5.1: popt-shlibs_1.7-5_darwin-powerpc.deb
Only in archive-tar-minitar-0.5.1: tar-1.14
halostatue commented 13 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