debian-mirror-gitlab/lib/safe_zip/extract.rb

54 lines
1.5 KiB
Ruby
Raw Normal View History

2019-02-02 18:00:53 +05:30
# frozen_string_literal: true
module SafeZip
class Extract
Error = Class.new(StandardError)
PermissionDeniedError = Class.new(Error)
SymlinkSourceDoesNotExistError = Class.new(Error)
UnsupportedEntryError = Class.new(Error)
AlreadyExistsError = Class.new(Error)
NoMatchingError = Class.new(Error)
ExtractError = Class.new(Error)
attr_reader :archive_path
def initialize(archive_file)
@archive_path = archive_file
end
def extract(opts = {})
params = SafeZip::ExtractParams.new(**opts)
2021-01-03 14:25:43 +05:30
extract_with_ruby_zip(params)
2019-02-02 18:00:53 +05:30
end
private
def extract_with_ruby_zip(params)
2022-01-26 12:08:38 +05:30
::Zip::File.open(archive_path) do |zip_archive| # rubocop:disable Performance/Rubyzip
2019-02-02 18:00:53 +05:30
# Extract all files in the following order:
# 1. Directories first,
# 2. Files next,
# 3. Symlinks last (or anything else)
extracted = extract_all_entries(zip_archive, params,
zip_archive.lazy.select(&:directory?))
extracted += extract_all_entries(zip_archive, params,
zip_archive.lazy.select(&:file?))
extracted += extract_all_entries(zip_archive, params,
zip_archive.lazy.reject(&:directory?).reject(&:file?))
raise NoMatchingError, 'No entries extracted' unless extracted > 0
end
end
def extract_all_entries(zip_archive, params, entries)
entries.count do |zip_entry|
SafeZip::Entry.new(zip_archive, zip_entry, params)
.extract
end
end
end
end