In my JAR file tool, I just encountered an issue on a Windows system.
When I build the tool for Linux it worked fine, but on Windows it did not display or update the files within the ZIP files.
It turned out, that the ZIP file library requires paths to the files within the archive to be POSIX style, i.e. with a / instead of a \. Because my program used native conversion of the paths to string, it obviously failed on windows.
I wrote a helper function to serialize the paths in an OS-independent manner:
/// Converts a `Path` to a string representation suitable for use in a ZIP file.
fn path_to_zip_file_path(path: &Path) -> Option<String> {
let mut components = Vec::new();
for component in path.components() {
components.push(component.as_os_str().to_str()?);
}
Some(components.join("/"))
}
I did not find such a functionality within the std::path library or the zip crate.
Do you know of any standard library features that do this, which I may have overlooked?
Update: I now went the other direction and implemented a method to get the entry of a ZIP file by path. I don't know why this is not part of the zip crate's API:
use std::io::{Read, Seek};
use std::path::Path;
use zip::ZipArchive;
use zip::read::ZipFile;
use zip::result::{ZipError, ZipResult};
pub trait ByPath<R>
where
R: Read,
{
/// Returns a file from the ZIP archive by its path.
fn by_path<T>(&mut self, path: T) -> ZipResult<ZipFile<'_, R>>
where
T: AsRef<Path>;
}
impl<R> ByPath<R> for ZipArchive<R>
where
R: Read + Seek,
{
fn by_path<T>(&mut self, path: T) -> ZipResult<ZipFile<'_, R>>
where
T: AsRef<Path>,
{
self.index_for_path(path)
.ok_or(ZipError::FileNotFound)
.and_then(|index| self.by_index(index))
}
}
To be clear, it's the generation of paths in your JAR properties file that's the issue, not that the zip crate is writing files with backslashes? The latter is a somewhat common bug (the default .net zip file writer used to do that!)
Arguably, the zip crate should be able to accept native relative paths when looking up entries (maybe it does?), but you would still have a presumably invalid JAR due to Windows paths being invalid in a properties file.
And no, it’s not related to the content of the properties files. Only the version value is set to the appropriate key. It is, in fact, the zip crate not “finding” paths if they’re serialized Windows-style.
I think, it’s the right approach. Recently I wrote zipping a directory in Rust. Take an attention to line: 547, it uses forward slash regardless of the underline system.