Handle symlinks #340
Replies: 8 comments
-
After reading the ZIP specification, I think we need to add stuff here: https://github.com/mvdnes/zip-rs/blob/master/src/read.rs#L408 I've started refactoring the code like this: while (reader.position() as usize) < data.len()
{
let kind = try!(reader.read_u16::<LittleEndian>());
let len = try!(reader.read_u16::<LittleEndian>());
match kind
{
// Zip64 extended information extra field
0x0001 => {
file.uncompressed_size = try!(reader.read_u64::<LittleEndian>());
file.compressed_size = try!(reader.read_u64::<LittleEndian>());
try!(reader.read_u64::<LittleEndian>()); // relative header offset
try!(reader.read_u32::<LittleEndian>()); // disk start number
},
// UNIX Extra Field
0x000d => {
let atime = try!(reader.read_u32::<LittleEndian>());
let mtime = try!(reader.read_u32::<LittleEndian>());
let uid = try!(reader.read_u16::<LittleEndian>());
let gid = try!(reader.read_u16::<LittleEndian>());
}
_ => { try!(reader.seek(io::SeekFrom::Current(len as i64))); },
};
} Now the problem is it never matches. It doesn't even match the original So I'm guessing Regards, |
Beta Was this translation helpful? Give feedback.
-
Just so you know, I'm now using |
Beta Was this translation helpful? Give feedback.
-
I would be interested in this library handling symlinks. I might make a PR at some point. |
Beta Was this translation helpful? Give feedback.
-
I'm running into the same issue. |
Beta Was this translation helpful? Give feedback.
-
Looks like symlinks are a non-standard, undocumented part of Info-ZIP, which we'd have to tease out of https://sourceforge.net/projects/infozip/files/. Yay. Afaict, the only real option is to use unix-style symlinks inside the archives, and special case them on other platforms. |
Beta Was this translation helpful? Give feedback.
-
I hacked up the following; throwing this out there in case someone wants to improve it (I don't know if I will get to it).. The following code works to extract symlinks (for my example zip files) - I can't say whether it will work with other zips.. fn extract_from_zip_file(zip_path: &Path, extract_to_dir: &Path) -> Result<bool> {
const S_IFLNK: u32 = 0o120000; // symbolic link
let archive_file = std::fs::File::open(zip_path)?;
let mut archive = zip::ZipArchive::new(archive_file)?;
for file_number in 0..archive.len() {
let mut next = archive.by_index(file_number).unwrap();
#[allow(deprecated)]
let sanitized_name = next.sanitized_name();
if next.is_dir() {
let extracted_folder_path = extract_to_dir.join(sanitized_name);
std::fs::create_dir_all(extracted_folder_path).unwrap();
} else if next.is_file() {
let extracted_file_path = extract_to_dir.join(sanitized_name);
// handle links - the link source is in the contents of the compressed file
// it is not actually compressed
if let Some(mode) = next.unix_mode() {
if mode & S_IFLNK == S_IFLNK {
let mut contents = Vec::new();
next.read_to_end(&mut contents)?;
#[cfg(target_family = "unix")]
{
// Needed to be able to call `OsString::from_vec(Vec<u8>)`
use std::os::unix::ffi::OsStringExt as _;
let link_path =
std::path::PathBuf::from(std::ffi::OsString::from_vec(contents));
std::os::unix::fs::symlink(link_path, extracted_file_path)?;
}
#[cfg(target_family = "windows")]
{
// TODO: Support non-UTF-8 paths (currently only works for paths which are valid UTF-8)
let link_path = String::from_utf8(contents)?;
std::os::windows::fs::symlink_file(link_path, extracted_file_path)?;
}
continue;
}
}
let mut buffer: Vec<u8> = Vec::new();
let _bytes_read = next.read_to_end(&mut buffer)?;
// Handle files where they are in a sub-directory but that directory hasn't
// been created yet (found with __MACOSX/.filename)
if let Some(parent) = extracted_file_path.parent() {
if !parent.exists() {
std::fs::create_dir_all(parent)?;
}
}
#[cfg(target_family = "unix")]
{
use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
let mode = next.unix_mode().unwrap() & 0o7777;
println!("{:?} {:?} ", extracted_file_path, mode);
let mut file = OpenOptions::new()
.mode(mode)
.create(true)
.write(true)
.truncate(true)
.open(extracted_file_path)?;
file.write_all(&buffer)?;
}
#[cfg(target_family = "windows")]
{
let mut file = std::fs::File::create(extracted_file_path)?;
file.set_len(0)?;
file.write_all(&buffer)?;
}
}
}
Ok(true)
} |
Beta Was this translation helpful? Give feedback.
-
Hi, It would be great to have some eyes on my PR (it's much better than the mess I posted above)
I have currently have a copy of this code running in my own project - it would be nice to switch back to |
Beta Was this translation helpful? Give feedback.
-
Some lovely resources abt this linked in the @markmmm's implementation PR: #213 (comment) |
Beta Was this translation helpful? Give feedback.
-
Hello,
I have a ZIP archive created on linux using the
--symlinks
option.So my archive contains symlinks.
Yet, when I extract the corresponding files, they end up being text files with the name of the symlink target as their content.
How can I detect/handle symlinks?
Regards,
Beta Was this translation helpful? Give feedback.
All reactions