1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
mod compile;

pub use self::compile::*;

use std::error;
use std::fmt;
use std::os::raw::c_int;

use crate::ERROR_CALLBACK_ERROR;
use crate::ERROR_CORRUPT_FILE;
use crate::ERROR_COULD_NOT_ATTACH_TO_PROCESS;
use crate::ERROR_COULD_NOT_MAP_FILE;
use crate::ERROR_COULD_NOT_OPEN_FILE;
use crate::ERROR_INSUFFICIENT_MEMORY;
use crate::ERROR_INTERNAL_FATAL_ERROR;
use crate::ERROR_INVALID_FILE;
use crate::ERROR_SCAN_TIMEOUT;
use crate::ERROR_SUCCESS;
use crate::ERROR_SYNTAX_ERROR;
use crate::ERROR_TOO_MANY_MATCHES;
use crate::ERROR_UNSUPPORTED_FILE_VERSION;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Error {
    /// Callback returned an error
    CallbackError,
    /// Rule file is corrupt
    CorruptFile,
    /// Could not attach to process
    CouldNotAttach,
    /// File could not be mapped into memory
    CouldNotMapFile,
    /// File could not be opened
    CouldNotOpenFile,
    /// Insufficient memory to complete the operation
    InsufficientMemory,
    /// Internal fatal error
    InternalFatalError,
    /// File is not a valid rules file
    InvalidFile,
    /// Timeouted during scan
    ScanTimeout,
    /// Syntax error in rule
    SyntaxError,
    /// Too many matches
    TooManyMatches,
    /// Rule file version is not supported
    UnsupportedFileVersion,
    /// Unknown Yara error
    Unknown(i32),
}

impl Error {
    pub fn from_code(code: c_int) -> Result<(), Error> {
        use self::Error::*;

        if code as u32 == ERROR_SUCCESS {
            return Ok(());
        }

        Err(match code as u32 {
            ERROR_CALLBACK_ERROR => CallbackError,
            ERROR_CORRUPT_FILE => CorruptFile,
            ERROR_COULD_NOT_ATTACH_TO_PROCESS => CouldNotAttach,
            ERROR_COULD_NOT_MAP_FILE => CouldNotMapFile,
            ERROR_COULD_NOT_OPEN_FILE => CouldNotOpenFile,
            ERROR_INSUFFICIENT_MEMORY => InsufficientMemory,
            ERROR_INTERNAL_FATAL_ERROR => InternalFatalError,
            ERROR_INVALID_FILE => InvalidFile,
            ERROR_SCAN_TIMEOUT => ScanTimeout,
            ERROR_SYNTAX_ERROR => SyntaxError,
            ERROR_TOO_MANY_MATCHES => TooManyMatches,
            ERROR_UNSUPPORTED_FILE_VERSION => UnsupportedFileVersion,
            _ => Unknown(code),
        })
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.clone().into())
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        self.clone().into()
    }
}

impl From<Error> for &'static str {
    fn from(error: Error) -> &'static str {
        use self::Error::*;

        match error {
            CallbackError => "Callback returned an error",
            CorruptFile => "Rule file is corrupt",
            CouldNotAttach => "Could not attach to process",
            CouldNotMapFile => "File could not be mapped into memory",
            CouldNotOpenFile => "File could not be opened",
            InsufficientMemory => "Insufficient memory to complete the operation",
            InternalFatalError => "Internal fatal error",
            InvalidFile => "File is not a valid rules file",
            ScanTimeout => "Timeouted during scan",
            SyntaxError => "Syntax error in rule",
            TooManyMatches => "Too many matches",
            UnsupportedFileVersion => "Rule file version is not supported",
            Unknown(_) => "Unknown Yara error",
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_error_from_code() {
        use super::Error::*;

        assert_eq!(Ok(()), Error::from_code(ERROR_SUCCESS as i32));
        assert_eq!(
            Err(InsufficientMemory),
            Error::from_code(ERROR_INSUFFICIENT_MEMORY as i32)
        );
        assert_eq!(
            Err(ScanTimeout),
            Error::from_code(ERROR_SCAN_TIMEOUT as i32)
        );
    }

    #[test]
    fn test_to_string() {
        use std::error::Error as StdError;
        assert_eq!(
            "Callback returned an error",
            Error::CallbackError.to_string()
        );
        assert_eq!(
            "Callback returned an error",
            Error::CallbackError.description()
        );
    }
}