2022-01-22 16:41:24 +00:00
|
|
|
// SPDX-FileCopyrightText: 2021-2022 Lynnesbian
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
2021-10-05 14:24:08 +00:00
|
|
|
|
2021-10-05 15:30:13 +00:00
|
|
|
//! The [`Findings`] and [`ScanError`] structs, used for conveying whether a given file was able to be scanned, whether
|
|
|
|
//! its MIME type could be inferred, and whether the file should be renamed.
|
2021-09-24 14:53:35 +00:00
|
|
|
|
2021-10-03 14:59:20 +00:00
|
|
|
use std::cmp::Ordering;
|
2021-09-24 08:11:25 +00:00
|
|
|
use std::fmt::{Display, Formatter};
|
2021-06-18 05:17:30 +00:00
|
|
|
use std::path::{Path, PathBuf};
|
2021-02-18 09:48:38 +00:00
|
|
|
|
2021-08-06 13:33:42 +00:00
|
|
|
use mime::Mime;
|
2021-09-24 08:11:25 +00:00
|
|
|
#[cfg(feature = "json")]
|
|
|
|
use serde::{ser::SerializeStruct, Serializer};
|
2021-02-14 17:12:27 +00:00
|
|
|
|
2021-08-28 08:09:15 +00:00
|
|
|
use crate::files::mime_extension_lookup;
|
2021-08-28 08:00:31 +00:00
|
|
|
use crate::String;
|
2021-02-18 09:48:38 +00:00
|
|
|
|
2021-10-05 15:30:13 +00:00
|
|
|
/// Information about a successfully scanned file.
|
2021-10-04 18:45:05 +00:00
|
|
|
#[derive(Eq, PartialEq, Debug)]
|
2021-06-18 05:17:30 +00:00
|
|
|
pub struct Findings {
|
2021-02-28 14:06:05 +00:00
|
|
|
/// The location of the scanned file.
|
2021-06-18 05:17:30 +00:00
|
|
|
pub file: PathBuf,
|
2021-11-24 20:29:27 +00:00
|
|
|
/// Whether or not the file's extension is valid for its MIME type.
|
2021-02-14 17:12:27 +00:00
|
|
|
pub valid: bool,
|
2021-11-24 20:29:27 +00:00
|
|
|
/// The file's MIME type.
|
2021-02-14 17:12:27 +00:00
|
|
|
pub mime: Mime,
|
|
|
|
}
|
|
|
|
|
2021-10-04 13:33:48 +00:00
|
|
|
impl Findings {
|
2021-10-04 14:18:42 +00:00
|
|
|
/// Returns the recommended extension for this file, if known.
|
2021-10-04 13:33:48 +00:00
|
|
|
pub fn recommended_extension(&self) -> Option<String> {
|
|
|
|
mime_extension_lookup(self.mime.essence_str().into()).map(|extensions| extensions[0].clone())
|
|
|
|
}
|
|
|
|
|
2021-10-04 14:18:42 +00:00
|
|
|
/// Returns the recommended path for this file - i.e. what it should be renamed to - if known.
|
2021-10-04 13:33:48 +00:00
|
|
|
pub fn recommended_path(&self) -> Option<PathBuf> {
|
2021-10-04 14:18:42 +00:00
|
|
|
self
|
|
|
|
.recommended_extension()
|
|
|
|
.map(|ext| self.file.with_extension(ext.as_str()))
|
2021-10-04 13:33:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-03 14:59:20 +00:00
|
|
|
impl PartialOrd<Self> for Findings {
|
2021-10-03 15:00:49 +00:00
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
|
2021-10-03 14:59:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Ord for Findings {
|
|
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
|
|
|
// files with no recommended extension should appear first, so that fif outputs the "no known extension for x"
|
|
|
|
// comments before the "mv x y" instructions
|
2021-10-03 15:00:49 +00:00
|
|
|
match (self.recommended_extension(), other.recommended_extension()) {
|
2021-10-03 14:59:20 +00:00
|
|
|
(None, Some(_)) => Ordering::Greater,
|
|
|
|
(Some(_), None) => Ordering::Less,
|
2021-10-03 15:00:49 +00:00
|
|
|
_ => self.file.cmp(&other.file),
|
2021-10-03 14:59:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-05 22:57:42 +00:00
|
|
|
#[cfg(feature = "json")]
|
2021-06-18 05:17:30 +00:00
|
|
|
impl serde::Serialize for Findings {
|
2021-05-05 23:06:05 +00:00
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: Serializer,
|
|
|
|
{
|
2021-05-05 22:57:42 +00:00
|
|
|
// the second parameter is the number of fields in the struct -- in this case, 3
|
|
|
|
let mut state = serializer.serialize_struct("Findings", 3)?;
|
|
|
|
|
|
|
|
state.serialize_field("file", &self.file)?;
|
|
|
|
state.serialize_field("valid", &self.valid)?;
|
|
|
|
state.serialize_field("mime", &self.mime.essence_str())?;
|
|
|
|
state.end()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-05 15:30:13 +00:00
|
|
|
/// Errors that can occur while scanning a file with [`scan_file`](crate::files::scan_file).
|
2021-05-05 23:27:16 +00:00
|
|
|
#[derive(Debug, PartialEq, PartialOrd, Ord, Eq)]
|
|
|
|
#[cfg_attr(feature = "json", derive(serde::Serialize))]
|
|
|
|
#[cfg_attr(feature = "json", serde(tag = "type", content = "path"))]
|
|
|
|
pub enum ScanError<'a> {
|
|
|
|
/// Something went wrong while trying to read the given file.
|
|
|
|
File(&'a Path),
|
2021-11-24 20:29:27 +00:00
|
|
|
/// Failed to determine the MIME type of the given file.
|
2021-05-05 23:27:16 +00:00
|
|
|
Mime(&'a Path),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Display for ScanError<'a> {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"Couldn't {} file: {}",
|
|
|
|
match self {
|
|
|
|
Self::File(_) => "read",
|
2021-11-24 20:29:27 +00:00
|
|
|
Self::Mime(_) => "determine MIME type of",
|
2021-05-05 23:27:16 +00:00
|
|
|
},
|
|
|
|
match self {
|
|
|
|
Self::File(f) | Self::Mime(f) => f.to_string_lossy(),
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|