Class: Archive::Tar::Reader

Inherits:
Object
  • Object
show all
Includes:
Archive::Tar
Defined in:
lib/archive/tar/reader.rb

Direct Known Subclasses

StreamReader

Constant Summary

Constants included from Archive::Tar

VERSION

Instance Method Summary collapse

Methods included from Archive::Tar

#join_path, #normalize_path, #solve_path

Constructor Details

#initialize(stream, options = {}) ⇒ Reader

Returns a new instance of Reader.



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/archive/tar/reader.rb', line 32

def initialize(stream, options = {})
  options = {
    compression: :auto,
    tmpdir: "/tmp",
    block_size: 2 ** 19,
    read_limit: 2 ** 19,
    cache: true,
    cache_size: 16,
    max_cache_size: 2 ** 19,
    generate_index: true,
    use_normalized_paths: true,
  }.merge(options)
  
  if stream.is_a? String
    stream = File.new(stream)
  end
  
  @options = options
  @stream = _generate_compressed_stream(stream, options[:compression])
  @cache_candidates = []
  @cache = {}
  
  build_index if options[:generate_index]
end

Instance Method Details

#[](file) ⇒ Object



76
77
78
# File 'lib/archive/tar/reader.rb', line 76

def [](file)
  stat(file, false)
end

#build_indexObject

Build new index of files



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/archive/tar/reader.rb', line 157

def build_index
  new_index = {}
  
  @stream.rewind
  
  until @stream.eof?
    raw_header = @stream.read(512)
    break if raw_header == "\0" * 512
    
    header = Archive::Tar::Format::unpack_header(raw_header)
    if @options[:use_normalized_paths]
      header[:path] = normalize_path(header[:path])
    end
    
    unless header[:type] == :pax_global_header
      new_index[header[:path]] = [ header, @stream.tell ]
    end
    
    @stream.seek(header[:blocks] * 512, IO::SEEK_CUR)
  end
  
  @index = new_index
end

#each(&block) ⇒ Object



88
89
90
91
92
# File 'lib/archive/tar/reader.rb', line 88

def each(&block)
  @index.each do |key, value|
    block.call(*(value))
  end
end

#entry?(file) ⇒ Boolean

Returns:

  • (Boolean)


84
85
86
# File 'lib/archive/tar/reader.rb', line 84

def entry?(file)
  has_entry? file
end

#extract(source, dest, options = {}) ⇒ Object

Extract file from /source/ to /dest/



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/archive/tar/reader.rb', line 134

def extract(source, dest, options = {})
  options = {
    recursive: true,
    preserve: false,
    override: false
  }.merge(options)
  unless @index.key? source
    raise NoSuchEntryError.new(source)
  end

  header, offset = @index[source]
  _extract(header, offset, dest, options)

  if header[:type] == :directory && options[:recursive]
    @index.each_key do |entry|
      if entry[0, source.length] == source && entry != source
        extract(entry, File.join(dest, entry.sub(source, "")), options)
      end
    end
  end
end

#extract_all(dest, options = {}) ⇒ Object

Extract all files to /dest/ directory



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/archive/tar/reader.rb', line 111

def extract_all(dest, options = {})
  options = {
    :preserve => false,
    :override => false
  }.merge(options)

  unless File::exists? dest
    FileUtils::mkdir_p dest
  end

  unless File.directory? dest
    raise "No such directory: #{dest}"
  end

  @index.each_key do |entry|
    ndest = File.join(dest, entry)
    header, offset = @index[entry]
    
    _extract(header, offset, ndest, options)
  end
end

#has_entry?(file) ⇒ Boolean

Returns:

  • (Boolean)


80
81
82
# File 'lib/archive/tar/reader.rb', line 80

def has_entry?(file)
  @index.key? file
end

#indexObject



61
62
63
# File 'lib/archive/tar/reader.rb', line 61

def index
  @index
end

#read(name, no_cache = false) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/archive/tar/reader.rb', line 94

def read(name, no_cache = false)
  header, offset = stat(name)
  
  if @options[:cache] && header[:size] <= @options[:max_cache_size] && !no_cache
    @cache_candidates << name
    rebuild_cache
  end
  
  if @cache.key? name && !no_cache
    return @cache[name]
  end
  
  @stream.seek(offset)
  @stream.read(header[:size])
end

#stat(file, exception = true) ⇒ Object

Raises:



65
66
67
68
69
70
71
72
73
74
# File 'lib/archive/tar/reader.rb', line 65

def stat(file, exception = true)
  if @options[:use_normalized_paths]
    result = @index[normalize_path(file)]
  else
    result = @index[file]
  end
  raise NoSuchEntryError.new(file) if result == nil && exception
  
  result
end

#streamObject



57
58
59
# File 'lib/archive/tar/reader.rb', line 57

def stream
  @stream
end