diff --git a/tar/src/header.rs b/tar/src/header.rs index a323c71..3bb8ea7 100644 --- a/tar/src/header.rs +++ b/tar/src/header.rs @@ -6,7 +6,7 @@ use std::{ fmt::{self, Write}, fs::{self, Metadata}, ops::Deref, - os::{linux::fs::MetadataExt, unix::fs::FileTypeExt}, + os::{linux::fs::MetadataExt, unix::fs::FileTypeExt}, path::PathBuf, io, }; #[repr(u8)] @@ -203,9 +203,36 @@ impl Header { }) } + pub fn prefix(&self) -> Result { + let mut s = String::new(); + for c in self.file_prefix { + if c != b'\0' { + write!(s, "{c}")?; + } else { + break; + } + } + Ok(s) + } + pub fn new(filename: &str) -> Result { let mut header = Header::default(); let meta = fs::symlink_metadata(filename)?; + let (filename, prefix) = if filename.len() < 100 { + (filename.to_string(), None) + } else { + // Deal with file names longer than 100 bytes + let path = PathBuf::from(&filename); + let name = match path.file_name().and_then(|n| n.to_str()) { + Some(n) => n.to_string(), + None => return Err(Error::Io(io::Error::new(io::ErrorKind::Other, "Cannot get file name"))), + }; + let dir = match path.parent() { + Some(d) => d, + None => return Err(Error::Io(io::Error::new(io::ErrorKind::Other, "Cannot get path prefix"))), + }; + (name, Some(format!("{}", dir.display()))) + }; /* Fill in metadata */ header.fname[..filename.len()].copy_from_slice(filename.as_bytes()); @@ -219,6 +246,9 @@ impl Header { header.size[..size.len()].copy_from_slice(size.as_bytes()); let mtime = format!("{:011o}", meta.st_mtime()); header.mtime[..mtime.len()].copy_from_slice(mtime.as_bytes()); + if let Some(prefix) = prefix { + header.file_prefix[..prefix.len()].copy_from_slice(prefix.as_bytes()); + } /* Get the file type and conditional metadata */ header.link_indicator[0] = FileType::from(&meta) as u8;