summaryrefslogtreecommitdiffstats
path: root/src/files.rs
diff options
context:
space:
mode:
authorrabite <rabite@posteo.de>2020-02-08 00:17:56 +0100
committerrabite <rabite@posteo.de>2020-02-08 00:17:56 +0100
commite3b4c997bf3f0075c6e1ecb282117d9cade3a440 (patch)
treed001ff84ecb5a134ce0d982ad38813164ea02aa1 /src/files.rs
parent6afca62010f2b6e7dc4921c4d4aa02ce5e5c3b33 (diff)
fix crash by catching tree_magic's panic and handle it gracefully
Diffstat (limited to 'src/files.rs')
-rw-r--r--src/files.rs53
1 files changed, 41 insertions, 12 deletions
diff --git a/src/files.rs b/src/files.rs
index 914f16f..d9f4534 100644
--- a/src/files.rs
+++ b/src/files.rs
@@ -961,23 +961,52 @@ impl File {
Ok((size as u32, unit))
}
- pub fn get_mime(&self) -> Option<mime_guess::Mime> {
+ // Sadly tree_magic tends to panic (in unwraps a None) when called
+ // with things like pipes, non-existing files. and other stuff. To
+ // prevent it from crashing hunter it's necessary to catch the
+ // panic with a custom panic hook and handle it gracefully by just
+ // doing nothing
+ pub fn get_mime(&self) -> HResult<mime_guess::Mime> {
+ use std::panic;
+ use crate::fail::MimeError;
+
if let Some(ext) = self.path.extension() {
let mime = mime_guess::from_ext(&ext.to_string_lossy()).first();
- mime
- } else {
- // Fix crash in tree_magic when called on non-regular file
- // Also fix crash when a file doesn't exist any more
- self.meta()
- .and_then(|meta| {
- if meta.is_file() && self.path.exists() {
- let mime = tree_magic::from_filepath(&self.path);
- mime::Mime::from_str(&mime).ok()
- } else { None }
- })
+ if mime.is_some() {
+ return Ok(mime.unwrap());
+ }
}
+
+ self.meta()
+ .map(|meta| {
+ // Take and replace panic handler which does nothing
+ let panic_hook = panic::take_hook();
+ panic::set_hook(Box::new(|_| {} ));
+
+ // Catch possible panic caused by tree_magic
+ let mime = panic::catch_unwind(|| {
+ match meta.is_file() && self.path.exists() {
+ true => {
+ let mime = tree_magic::from_filepath(&self.path);
+ mime::Mime::from_str(&mime).ok()
+ }
+ false => None
+ }
+ });
+
+ // Restore previous panic handler
+ panic::set_hook(panic_hook);
+
+ mime
+ }).unwrap_or(Ok(None))
+ .unwrap_or(None)
+ .ok_or_else(|| {
+ let file = self.name.clone();
+ HError::Mime(MimeError::Panic(file))
+ })
}
+
pub fn is_text(&self) -> bool {
tree_magic::match_filepath("text/plain", &self.path)
}