require "fileutils" module Ddr::Antivirus # # Adapter for clamd client (clamdscan) # class ClamdScannerAdapter < ScannerAdapter 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 raise VirusFoundError.new(result) when 2 raise ScannerError.new(result) end end def clamdscan(path) output = IO.popen(["clamdscan", "--fdpass", path, err: [:child, :out]]) do |io| io.read end [ output, $?.exitstatus ] end def version @version ||= `clamdscan -V`.strip end def max_file_size @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 at \"#{path}\" -- size (#{file_size}) " \ "exceeds clamd MaxFileSize setting (#{max_file_size})." end end end end