excavate 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,44 @@
1
+ require_relative "cpio/cpio"
2
+ require_relative "cpio/cpio_old_format"
3
+
4
+ module Excavate
5
+ module Extractors
6
+ class CpioExtractor < Extractor
7
+ def extract(target)
8
+ extract_cpio_new_format(target)
9
+ rescue RuntimeError => e
10
+ raise unless e.message.start_with?("Invalid magic")
11
+
12
+ extract_cpio_old_format(target)
13
+ end
14
+
15
+ private
16
+
17
+ def extract_cpio_new_format(target)
18
+ File.open(@archive, "rb") do |archive_file|
19
+ CPIO::ASCIIReader.new(archive_file).each do |entry, file|
20
+ path = File.join(target, entry.name)
21
+ if entry.directory?
22
+ FileUtils.mkdir_p(path)
23
+ else
24
+ File.write(path, file.read, mode: "wb")
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ def extract_cpio_old_format(target)
31
+ File.open(@archive, "rb") do |archive_file|
32
+ CPIO::ArchiveReader.new(archive_file).each_entry do |entry|
33
+ path = File.expand_path(entry.filename, target)
34
+ if entry.directory?
35
+ FileUtils.mkdir_p(path)
36
+ else
37
+ File.write(path, entry.data, mode: "wb")
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,13 @@
1
+ module Excavate
2
+ module Extractors
3
+ class Extractor
4
+ def initialize(archive)
5
+ @archive = archive
6
+ end
7
+
8
+ def extract(_target)
9
+ raise NotImplementedError.new("You must implement this method")
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Excavate
2
+ module Extractors
3
+ class GzipExtractor < Extractor
4
+ def extract(target)
5
+ Zlib::GzipReader.open(@archive) do |gz|
6
+ basename = File.basename(@archive, ".*")
7
+ path = File.join(target, basename)
8
+ File.write(path, gz.read, mode: "wb")
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,66 @@
1
+ require "ole/storage"
2
+
3
+ module Excavate
4
+ module Extractors
5
+ class OleExtractor < Extractor
6
+ def extract(target)
7
+ do_extract(target)
8
+ rename_archives(target)
9
+ end
10
+
11
+ private
12
+
13
+ def do_extract(target)
14
+ reset_filename_lookup
15
+
16
+ Ole::Storage.open(@archive) do |ole|
17
+ children(ole).each do |file|
18
+ filename = prepare_filename(file)
19
+ path = File.join(target, filename)
20
+ content = ole.file.read(file)
21
+ File.write(path, content, mode: "wb")
22
+ end
23
+ end
24
+ end
25
+
26
+ def children(ole)
27
+ ole.dir.entries(".") - [".", ".."]
28
+ end
29
+
30
+ def reset_filename_lookup
31
+ @file_lookup = {}
32
+ end
33
+
34
+ def prepare_filename(file)
35
+ filename = sanitize_filename(file)
36
+
37
+ @file_lookup[filename] ||= 0
38
+ @file_lookup[filename] += 1
39
+ filename += @file_lookup[filename].to_s if @file_lookup[filename] > 1
40
+
41
+ filename
42
+ end
43
+
44
+ def sanitize_filename(filename)
45
+ filename.strip.tap do |name|
46
+ # NOTE: File.basename doesn't work right with Windows paths on Unix
47
+ # get only the filename, not the whole path
48
+ name.gsub!(/^.*(\\|\/)/, "")
49
+
50
+ # Strip out the non-ascii character
51
+ name.gsub!(/[^0-9A-Za-z.\-]/, "_")
52
+ end
53
+ end
54
+
55
+ def rename_archives(target)
56
+ Dir.glob(File.join(target, "**", "*")).each do |file|
57
+ FileUtils.mv(file, "#{file}.cab") if cab?(file)
58
+ end
59
+ end
60
+
61
+ def cab?(file)
62
+ FileMagic.detect(file) == :cab
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,33 @@
1
+ require "arr-pm"
2
+
3
+ # fix for Ruby 3.0
4
+ unless RPM::File::Header::HEADER_MAGIC == "\x8e\xad\xe8\x01\x00\x00\x00\x00".force_encoding("BINARY")
5
+ RPM::File::Header.send(:remove_const, "HEADER_MAGIC")
6
+ RPM::File::Header.const_set("HEADER_MAGIC", "\x8e\xad\xe8\x01\x00\x00\x00\x00".force_encoding("BINARY"))
7
+ end
8
+
9
+ module Excavate
10
+ module Extractors
11
+ class RpmExtractor < Extractor
12
+ def extract(target)
13
+ File.open(@archive, "rb") do |file|
14
+ rpm = RPM::File.new(file)
15
+ content = rpm.payload.read
16
+ path = target_path(@archive, rpm.tags, target)
17
+
18
+ File.write(path, content, mode: "wb")
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def target_path(archive, tags, dir)
25
+ archive_format = tags[:payloadformat]
26
+ compression_format = tags[:payloadcompressor] == "gzip" ? "gz" : tags[:payloadcompressor]
27
+ basename = File.basename(archive, ".*")
28
+ filename = basename + "." + archive_format + "." + compression_format
29
+ File.join(dir, filename)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,13 @@
1
+ require "seven_zip_ruby"
2
+
3
+ module Excavate
4
+ module Extractors
5
+ class SevenZipExtractor < Extractor
6
+ def extract(target)
7
+ File.open(@archive, "rb") do |file|
8
+ SevenZipRuby::Reader.extract_all(file, target)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,29 @@
1
+ require "rubygems/package"
2
+
3
+ module Excavate
4
+ module Extractors
5
+ class TarExtractor < Extractor
6
+ def extract(target)
7
+ File.open(@archive, "rb") do |archive_file|
8
+ Gem::Package::TarReader.new(archive_file) do |tar|
9
+ tar.each do |tarfile|
10
+ save_tar_file(tarfile, target)
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def save_tar_file(file, dir)
19
+ path = File.join(dir, file.full_name)
20
+
21
+ if file.directory?
22
+ FileUtils.mkdir_p(path)
23
+ else
24
+ File.write(path, file.read, mode: "wb")
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,17 @@
1
+ require "zip"
2
+
3
+ module Excavate
4
+ module Extractors
5
+ class ZipExtractor < Extractor
6
+ def extract(target)
7
+ Zip::File.open(@archive) do |zip_file|
8
+ zip_file.each do |entry|
9
+ path = File.join(target, entry.name)
10
+ FileUtils.mkdir_p(File.dirname(path))
11
+ entry.extract(path)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ module Excavate
2
+ class FileMagic
3
+ def self.detect(path)
4
+ new(path).detect
5
+ end
6
+
7
+ def initialize(path)
8
+ @path = path
9
+ end
10
+
11
+ def detect
12
+ case File.read(@path, 8, mode: "rb")
13
+ when "MSCF\x00\x00\x00\x00".force_encoding("BINARY")
14
+ :cab
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ module Excavate
2
+ module Utils
3
+ module_function
4
+
5
+ def silence_stream(stream)
6
+ old_stream = stream.dup
7
+ stream.reopen(RbConfig::CONFIG["host_os"] =~ /mswin|mingw/ ? "NUL:" : "/dev/null") # rubocop:disable Performance/RegexpMatch, Metrics/LineLength
8
+ stream.sync = true
9
+ yield
10
+ ensure
11
+ stream.reopen(old_stream)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Excavate
4
+ VERSION = "0.1.0"
5
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: excavate
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ribose Inc.
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-02-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: arr-pm
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: libmspack
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: ruby-ole
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubyzip
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.3'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: seven_zip_ruby
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.0'
83
+ description: Extract nested archives with a single command.
84
+ email:
85
+ - open.source@ribose.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".github/workflows/release.yml"
91
+ - ".github/workflows/rspec.yml"
92
+ - ".gitignore"
93
+ - ".rspec"
94
+ - ".rubocop.yml"
95
+ - Gemfile
96
+ - LICENSE.adoc
97
+ - README.adoc
98
+ - Rakefile
99
+ - excavate.gemspec
100
+ - lib/excavate.rb
101
+ - lib/excavate/archive.rb
102
+ - lib/excavate/extractors.rb
103
+ - lib/excavate/extractors/cab_extractor.rb
104
+ - lib/excavate/extractors/cpio/cpio.rb
105
+ - lib/excavate/extractors/cpio/cpio_old_format.rb
106
+ - lib/excavate/extractors/cpio_extractor.rb
107
+ - lib/excavate/extractors/extractor.rb
108
+ - lib/excavate/extractors/gzip_extractor.rb
109
+ - lib/excavate/extractors/ole_extractor.rb
110
+ - lib/excavate/extractors/rpm_extractor.rb
111
+ - lib/excavate/extractors/seven_zip_extractor.rb
112
+ - lib/excavate/extractors/tar_extractor.rb
113
+ - lib/excavate/extractors/zip_extractor.rb
114
+ - lib/excavate/file_magic.rb
115
+ - lib/excavate/utils.rb
116
+ - lib/excavate/version.rb
117
+ homepage: https://github.com/fontist/excavate
118
+ licenses:
119
+ - BSD-3-Clause
120
+ metadata:
121
+ homepage_uri: https://github.com/fontist/excavate
122
+ source_code_uri: https://github.com/fontist/excavate
123
+ changelog_uri: https://github.com/fontist/excavate
124
+ post_install_message:
125
+ rdoc_options: []
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ requirements: []
139
+ rubygems_version: 3.0.3
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: Extract nested archives with a single command.
143
+ test_files: []