lib/ddr/antivirus/adapters/clamd_scanner_adapter.rb in ddr-antivirus-2.2.0 vs lib/ddr/antivirus/adapters/clamd_scanner_adapter.rb in ddr-antivirus-3.0.0.rc1
- old
+ new
@@ -1,21 +1,26 @@
require "fileutils"
-require "shellwords"
module Ddr::Antivirus
#
# Adapter for clamd client (clamdscan)
#
class ClamdScannerAdapter < ScannerAdapter
- SCANNER = "clamdscan".freeze
- CONFIG = "clamconf".freeze
-
MAX_FILE_SIZE_RE = Regexp.new('^MaxFileSize = "(\d+)"')
+ DEFAULT_MAX_FILE_SIZE = 26214400 # 25Mb
+ attr_reader :config
+
+ def initialize
+ @config = `clamconf` rescue nil
+ end
+
def scan(path)
+ check_file_size(path) # raises Ddr::Antivirus::MaxFileSizeExceeded
output, exitcode = clamdscan(path)
+ # FIXME I don't like where the scanned_at time is set, but I'm nit-picking --DCS
result = ScanResult.new(path, output, version: version, scanned_at: Time.now.utc)
case exitcode
when 0
result
when 1
@@ -24,63 +29,35 @@
raise ScannerError.new(result)
end
end
def clamdscan(path)
- check_file_size(path) if max_file_size
- output = make_readable(path) do
- command "--fdpass", safe_path(path)
+ output = IO.popen(["clamdscan", "--fdpass", path, err: [:child, :out]]) do |io|
+ io.read
end
[ output, $?.exitstatus ]
end
def version
- @version ||= command("-V").strip
+ @version ||= `clamdscan -V`.strip
end
- def config
- # If client and server are on separate hosts
- # attempt to read config may raise an exception.
- @config ||= `#{CONFIG}` rescue nil
- end
-
def max_file_size
- if m = MAX_FILE_SIZE_RE.match(config)
- m[1].to_i
- end
+ @max_file_size ||= if config && (m = MAX_FILE_SIZE_RE.match(config))
+ m[1].to_i
+ else
+ DEFAULT_MAX_FILE_SIZE
+ end
end
private
def check_file_size(path)
if (file_size = File.size(path)) > max_file_size
- raise MaxFileSizeExceeded, "Unable to scan file \"#{path}\" because size (#{file_size})" \
- " exceeds clamconf MaxFileSize (#{max_file_size})."
+ raise MaxFileSizeExceeded,
+ "Unable to scan file at \"#{path}\" -- size (#{file_size}) " \
+ "exceeds clamd MaxFileSize setting (#{max_file_size})."
end
- end
-
- def command(*args)
- cmd = args.dup.unshift(SCANNER).join(" ")
- `#{cmd}`
- end
-
- def make_readable(path)
- changed = false
- original = File.stat(path).mode # raises Errno::ENOENT
- if !File.world_readable?(path)
- changed = FileUtils.chmod("a+r", path)
- logger.debug "#{self.class} - File \"#{path}\" made world-readable."
- end
- result = yield
- if changed
- FileUtils.chmod(original, path)
- logger.debug "#{self.class} - Mode on file \"#{path}\" reset to original: #{original}."
- end
- result
- end
-
- def safe_path(path)
- Shellwords.shellescape(path)
end
end
end