I'm developing a game save manager using Tauri and Rust. The tool compresses and decompresses game saves using the zip crate. However, users have reported that the tool disrupts the order of save files in games that sort saves based on their last modification time. This occurs because when restoring saves, the files are given the current system time instead of their original modification time. I've attempted to preserve the original modification times during the compression process, but I'm encountering difficulties when trying to restore these times during decompression, particularly on Windows 11.
When compressing files, I store the original modification time in the zip file using the last_modified_time
option of SimpleFileOptions
. This seems to work correctly, as I can verify the correct times are stored in the zip file.
let mut original_file = File::open(&unit_path)?;
let last_modify_time = original_file.metadata()?.modified()?;
let last_modify_time =
chrono::DateTime::<Local>::from(last_modify_time).naive_local();
let mut buf = vec![];
original_file.read_to_end(&mut buf)?;
zip.start_file(
unit_path
.file_name()
.ok_or(BackupFileError::NonePathError)?
.to_str()
.ok_or(BackupFileError::NonePathError)?,
SimpleFileOptions::default()
.compression_method(zip::CompressionMethod::Bzip2)
.last_modified_time(last_modify_time.try_into().unwrap()),
)?;
This approach correctly stores the time in the zip file. Is this method reliable? For folders, I'm recursively applying this process to files within the folder, but I'm unsure if this is the correct approach.
When decompressing, I attempt to read the stored modification time from the zip file and set it on the extracted file using File::set_modified()
. However, this results in a "Permission denied" error on Windows 11.
let option = fs_extra::file::CopyOptions::new().overwrite(true);
let last_modified = zip
.by_name(original_path.file_name().unwrap().to_str().unwrap())
.unwrap()
.last_modified()
.unwrap();
let last_modified = chrono::NaiveDateTime::try_from(last_modified)
.unwrap()
.and_local_timezone(Local)
.unwrap()
.timestamp();
let last_modified =
UNIX_EPOCH + std::time::Duration::from_secs(last_modified as u64);
File::open(&original_path)
.unwrap()
.set_modified(last_modified)
.unwrap(); // this line panic! "Permission denied"
fs_extra::file::move_file(&original_path, &unit_path, &option)?;
I expected these steps to preserve the original modification times of the files throughout the compression and decompression process. Instead, while I can successfully store the times, I'm unable to apply them when extracting the files due to permission issues. I'm unsure if my approach is correct or if there's a more efficient way to handle file metadata in this context.
As a side note, while I'm developing on Windows, I aim for the program to run on Linux or macOS as well. Therefore, I'm looking for a cross-platform solution to this issue.