Always uncompress entire rar archive
To avoid libarchive bugs.
This commit is contained in:
parent
af5c11acc7
commit
fd8015024f
175
src/main.rs
175
src/main.rs
@ -13,7 +13,7 @@ use std::time::Duration;
|
|||||||
use tempfile::tempdir;
|
use tempfile::tempdir;
|
||||||
use tokio::io::{AsyncReadExt, AsyncSeekExt};
|
use tokio::io::{AsyncReadExt, AsyncSeekExt};
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
use tracing::{debug, error, info, info_span, warn};
|
use tracing::{debug, info, info_span, warn};
|
||||||
use unrar::Archive;
|
use unrar::Archive;
|
||||||
use zip::write::{FileOptions, ZipWriter};
|
use zip::write::{FileOptions, ZipWriter};
|
||||||
|
|
||||||
@ -228,31 +228,93 @@ pub async fn main() -> Result<()> {
|
|||||||
"inferred mime_type of downloaded archive"
|
"inferred mime_type of downloaded archive"
|
||||||
);
|
);
|
||||||
|
|
||||||
tokio_file.seek(SeekFrom::Start(0)).await?;
|
match kind.mime_type() {
|
||||||
let mut file = tokio_file.try_clone().await?.into_std().await;
|
"application/vnd.rar" => {
|
||||||
let mut plugin_file_paths = Vec::new();
|
info!("downloaded archive is RAR archive, attempt to uncompress entire archive");
|
||||||
|
// Use unrar to uncompress the entire .rar file to avoid bugs with compress_tools uncompressing certain .rar files:
|
||||||
|
// https://github.com/libarchive/libarchive/issues/373, https://github.com/libarchive/libarchive/issues/1426
|
||||||
|
tokio_file.seek(SeekFrom::Start(0)).await?;
|
||||||
|
let mut file = tokio_file.try_clone().await?.into_std().await;
|
||||||
|
let temp_dir = tempdir()?;
|
||||||
|
let temp_file_path = temp_dir.path().join("download.rar");
|
||||||
|
let mut temp_file = std::fs::File::create(&temp_file_path)?;
|
||||||
|
std::io::copy(&mut file, &mut temp_file)?;
|
||||||
|
|
||||||
for file_name in list_archive_files(&file)? {
|
let mut plugin_file_paths = Vec::new();
|
||||||
if file_name.ends_with(".esp")
|
let list =
|
||||||
|| file_name.ends_with(".esm")
|
Archive::new(temp_file_path.to_string_lossy().to_string()).list();
|
||||||
|| file_name.ends_with(".esl")
|
if let Ok(list) = list {
|
||||||
{
|
for entry in list {
|
||||||
plugin_file_paths.push(file_name);
|
if let Ok(entry) = entry {
|
||||||
|
if entry.filename.ends_with(".esp")
|
||||||
|
|| entry.filename.ends_with(".esm")
|
||||||
|
|| entry.filename.ends_with(".esl")
|
||||||
|
{
|
||||||
|
plugin_file_paths.push(entry.filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info!(
|
||||||
|
num_plugin_files = plugin_file_paths.len(),
|
||||||
|
"listed plugins in downloaded archive"
|
||||||
|
);
|
||||||
|
|
||||||
|
if plugin_file_paths.len() > 0 {
|
||||||
|
info!("uncompressing downloaded archive");
|
||||||
|
let extract =
|
||||||
|
Archive::new(temp_file_path.to_string_lossy().to_string())
|
||||||
|
.extract_to(temp_dir.path().to_string_lossy().to_string());
|
||||||
|
extract
|
||||||
|
.expect("failed to extract")
|
||||||
|
.process()
|
||||||
|
.expect("failed to extract");
|
||||||
|
|
||||||
|
for file_name in plugin_file_paths.iter() {
|
||||||
|
info!(
|
||||||
|
?file_name,
|
||||||
|
"processing uncompressed file from downloaded archive"
|
||||||
|
);
|
||||||
|
let mut plugin_buf =
|
||||||
|
std::fs::read(temp_dir.path().join(file_name))?;
|
||||||
|
process_plugin(
|
||||||
|
&mut plugin_buf,
|
||||||
|
&pool,
|
||||||
|
&mut plugins_archive,
|
||||||
|
&db_file,
|
||||||
|
&db_mod,
|
||||||
|
file_name,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
temp_dir.close()?;
|
||||||
}
|
}
|
||||||
}
|
_ => {
|
||||||
info!(
|
tokio_file.seek(SeekFrom::Start(0)).await?;
|
||||||
num_plugin_files = plugin_file_paths.len(),
|
let mut file = tokio_file.try_clone().await?.into_std().await;
|
||||||
"listed plugins in downloaded archive"
|
let mut plugin_file_paths = Vec::new();
|
||||||
);
|
|
||||||
|
|
||||||
for file_name in plugin_file_paths.iter() {
|
for file_name in list_archive_files(&file)? {
|
||||||
let plugin_span = info_span!("plugin", name = ?file_name);
|
if file_name.ends_with(".esp")
|
||||||
let _plugin_span = plugin_span.enter();
|
|| file_name.ends_with(".esm")
|
||||||
file.seek(SeekFrom::Start(0))?;
|
|| file_name.ends_with(".esl")
|
||||||
info!("attempting to uncompress plugin file from downloaded archive");
|
{
|
||||||
let mut buf = Vec::default();
|
plugin_file_paths.push(file_name);
|
||||||
match uncompress_archive_file(&mut file, &mut buf, file_name) {
|
}
|
||||||
Ok(_) => {
|
}
|
||||||
|
info!(
|
||||||
|
num_plugin_files = plugin_file_paths.len(),
|
||||||
|
"listed plugins in downloaded archive"
|
||||||
|
);
|
||||||
|
|
||||||
|
for file_name in plugin_file_paths.iter() {
|
||||||
|
let plugin_span = info_span!("plugin", name = ?file_name);
|
||||||
|
let _plugin_span = plugin_span.enter();
|
||||||
|
file.seek(SeekFrom::Start(0))?;
|
||||||
|
let mut buf = Vec::default();
|
||||||
|
info!("uncompressing plugin file from downloaded archive");
|
||||||
|
uncompress_archive_file(&mut file, &mut buf, file_name)?;
|
||||||
process_plugin(
|
process_plugin(
|
||||||
&mut buf,
|
&mut buf,
|
||||||
&pool,
|
&pool,
|
||||||
@ -263,73 +325,6 @@ pub async fn main() -> Result<()> {
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
Err(error) => {
|
|
||||||
warn!(
|
|
||||||
?error,
|
|
||||||
"error occurred while attempting to uncompress archive file"
|
|
||||||
);
|
|
||||||
if kind.mime_type() == "application/x-rar-compressed"
|
|
||||||
|| kind.mime_type() == "application/vnd.rar"
|
|
||||||
{
|
|
||||||
info!("downloaded archive is RAR archive, attempt to uncompress entire archive instead");
|
|
||||||
// Use unrar to uncompress the entire .rar file to avoid a bug with compress_tools panicking when uncompressing
|
|
||||||
// certain .rar files: https://github.com/libarchive/libarchive/issues/373
|
|
||||||
tokio_file.seek(SeekFrom::Start(0)).await?;
|
|
||||||
let mut file = tokio_file.try_clone().await?.into_std().await;
|
|
||||||
let temp_dir = tempdir()?;
|
|
||||||
let temp_file_path = temp_dir.path().join("download.rar");
|
|
||||||
let mut temp_file = std::fs::File::create(&temp_file_path)?;
|
|
||||||
std::io::copy(&mut file, &mut temp_file)?;
|
|
||||||
|
|
||||||
let mut plugin_file_paths = Vec::new();
|
|
||||||
let list =
|
|
||||||
Archive::new(temp_file_path.to_string_lossy().to_string())
|
|
||||||
.list();
|
|
||||||
if let Ok(list) = list {
|
|
||||||
for entry in list {
|
|
||||||
if let Ok(entry) = entry {
|
|
||||||
if entry.filename.ends_with(".esp")
|
|
||||||
|| entry.filename.ends_with(".esm")
|
|
||||||
|| entry.filename.ends_with(".esl")
|
|
||||||
{
|
|
||||||
plugin_file_paths.push(entry.filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if plugin_file_paths.len() > 0 {
|
|
||||||
let extract =
|
|
||||||
Archive::new(temp_file_path.to_string_lossy().to_string())
|
|
||||||
.extract_to(
|
|
||||||
temp_dir.path().to_string_lossy().to_string(),
|
|
||||||
);
|
|
||||||
extract
|
|
||||||
.expect("failed to extract")
|
|
||||||
.process()
|
|
||||||
.expect("failed to extract");
|
|
||||||
for file_name in plugin_file_paths.iter() {
|
|
||||||
info!(
|
|
||||||
?file_name,
|
|
||||||
"processing uncompressed file from downloaded archive"
|
|
||||||
);
|
|
||||||
let mut plugin_buf =
|
|
||||||
std::fs::read(temp_dir.path().join(file_name))?;
|
|
||||||
process_plugin(
|
|
||||||
&mut plugin_buf,
|
|
||||||
&pool,
|
|
||||||
&mut plugins_archive,
|
|
||||||
&db_file,
|
|
||||||
&db_mod,
|
|
||||||
file_name,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
temp_dir.close()?;
|
|
||||||
}
|
|
||||||
error!(mime_type = ?kind.mime_type(), "downloaded archive is not RAR archive, skipping processing of this file");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user