How to preserve file modification times when zipping and unzipping in Rust?

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.

After receiving some help, I am able to write the meta information of the file using OpenOptions::new().read(true). open(), but I cannot find how to handle the folder

I've found a crate fs_set_times can set the last modified time for a folder.

I have posted a related question on Stack Overflow, and if I solve this problem, I will answer it myself. If you want to get more useful information, you can refer to this link windows - How to preserve file modification times when zipping and unzipping in Rust? - Stack Overflow

Thanks for letting us know about the crosspost!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.