mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-14 14:32:14 +00:00
Preserve ZIP directory semantics in bundle reader
This commit is contained in:
1 parent
a2e0f58632
commit
7c10820123
3 files changed
+17
-4
No files matched your search
@@ -95,10 +95,11 @@ pub fn read_bundle(bytes: &[u8], limits: BundleLimits) -> Result<(String, HashMa
|
||||
let mut session = None;
|
||||
let mut files = HashMap::new();
|
||||
for index in 0..len {
|
||||
let name = archive.entry_name(index).map_err(zip_error)?.ok_or_else(|| BundleError::Invalid("missing entry".into()))?;
|
||||
if name.ends_with('/') {
|
||||
let is_dir = archive.entry_is_dir(index).map_err(zip_error)?.ok_or_else(|| BundleError::Invalid("missing entry".into()))?;
|
||||
if is_dir {
|
||||
continue;
|
||||
}
|
||||
let name = archive.entry_name(index).map_err(zip_error)?.ok_or_else(|| BundleError::Invalid("missing entry".into()))?;
|
||||
let is_session = !name.contains('/') && Path::new(&name).extension().and_then(OsStr::to_str) == Some(SESSION_EXTENSION);
|
||||
let size = archive.declared_size(&name).ok_or_else(|| BundleError::Invalid(format!("{name}: missing entry")))?;
|
||||
if is_session && session.is_none() {
|
||||
|
||||
@@ -78,6 +78,15 @@ impl<'a> Archive<'a> {
|
||||
Ok(Some(name.into_owned()))
|
||||
}
|
||||
|
||||
/// Whether the entry at `index` is a directory according to ZIP filename conventions.
|
||||
pub fn entry_is_dir(&mut self, index: usize) -> Result<Option<bool>, Error> {
|
||||
if index >= self.zip.len() {
|
||||
return Ok(None);
|
||||
}
|
||||
let file = self.zip.by_index_raw(index).map_err(|error| Error::NotZip(error.to_string()))?;
|
||||
Ok(Some(file.is_dir()))
|
||||
}
|
||||
|
||||
/// Do two entries share a name? `zip` then keeps one of them, and which one a writer meant
|
||||
/// is not known: a format that must not guess refuses the archive.
|
||||
pub fn has_duplicate_names(&self) -> bool {
|
||||
|
||||
@@ -231,11 +231,14 @@ mod tests {
|
||||
zip.write_all(b"1").unwrap();
|
||||
zip.start_file("second", opts).unwrap();
|
||||
zip.write_all(b"2").unwrap();
|
||||
zip.start_file("folder\\", opts).unwrap();
|
||||
let bytes = zip.finish().unwrap().into_inner();
|
||||
|
||||
let mut archive = Archive::open(&bytes, Limits { max_entries: 2, max_total_bytes: 10 }).unwrap();
|
||||
let mut archive = Archive::open(&bytes, Limits { max_entries: 3, max_total_bytes: 10 }).unwrap();
|
||||
assert_eq!(archive.entry_name(0).unwrap().as_deref(), Some("first"));
|
||||
assert_eq!(archive.entry_name(1).unwrap().as_deref(), Some("second"));
|
||||
assert_eq!(archive.entry_name(2).unwrap(), None);
|
||||
assert_eq!(archive.entry_is_dir(2).unwrap(), Some(true));
|
||||
assert_eq!(archive.entry_name(2).unwrap().as_deref(), Some("folder\\"));
|
||||
assert_eq!(archive.entry_name(3).unwrap(), None);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user