2 # Copyright (C) 2004 Mauricio Julio Fernández Pradier
3 # See LICENSE.txt for additional licensing information.
6 require 'rubygems/package'
8 class Gem::Package::TarWriter
10 class FileOverflow < StandardError; end
14 attr_reader :limit, :written
16 def initialize(io, limit)
23 if data.size + @written > @limit
24 raise FileOverflow, "You tried to feed more data than fits in the file."
33 class RestrictedStream
48 return writer unless block_given?
64 def add_file(name, mode)
67 raise Gem::Package::NonSeekableIO unless @io.respond_to? :pos=
69 name, prefix = split_name name
72 @io.write "\0" * 512 # placeholder for the header
74 yield RestrictedStream.new(@io) if block_given?
76 size = @io.pos - init_pos - 512
78 remainder = (512 - (size % 512)) % 512
79 @io.write "\0" * remainder
84 header = Gem::Package::TarHeader.new :name => name, :mode => mode,
85 :size => size, :prefix => prefix
93 def add_file_simple(name, mode, size)
96 name, prefix = split_name name
98 header = Gem::Package::TarHeader.new(:name => name, :mode => mode,
99 :size => size, :prefix => prefix).to_s
102 os = BoundedStream.new @io, size
104 yield os if block_given?
106 min_padding = size - os.written
107 @io.write("\0" * min_padding)
109 remainder = (512 - (size % 512)) % 512
110 @io.write("\0" * remainder)
116 raise IOError, "closed #{self.class}" if closed?
122 @io.write "\0" * 1024
135 @io.flush if @io.respond_to? :flush
138 def mkdir(name, mode)
141 name, prefix = split_name(name)
143 header = Gem::Package::TarHeader.new :name => name, :mode => mode,
144 :typeflag => "5", :size => 0,
152 def split_name(name) # :nodoc:
153 raise Gem::Package::TooLongFileName if name.size > 256
155 if name.size <= 100 then
158 parts = name.split(/\//)
164 break if newname.size + 1 + nxt.size > 100
165 newname = nxt + "/" + newname
168 prefix = (parts + [nxt]).join "/"
171 if name.size > 100 or prefix.size > 155 then
172 raise Gem::Package::TooLongFileName