Fix some issues with getting tar header fields; Add some doc tests in
tar module; Add some tests for version checks;
This commit is contained in:
parent
acbdf2d992
commit
32b4f80715
@ -117,25 +117,45 @@ impl Default for Header {
|
||||
}
|
||||
|
||||
impl Header {
|
||||
/// Gets the filename of this archive member
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use hpk_package::tar::Header;
|
||||
///
|
||||
/// let header = Header::new("test/1.txt").unwrap();
|
||||
/// let filename = header.filename().unwrap();
|
||||
/// assert_eq!(filename.as_str(), "1.txt");
|
||||
/// ```
|
||||
pub fn filename(&self) -> Result<String, fmt::Error> {
|
||||
let mut s = String::new();
|
||||
for c in self.fname {
|
||||
if c != b'\0' {
|
||||
write!(s, "{c}")?;
|
||||
} else {
|
||||
if c == 0 {
|
||||
break;
|
||||
} else {
|
||||
write!(s, "{}", char::from(c))?;
|
||||
}
|
||||
}
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
/// Gets the Unix mode of this archive member
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use hpk_package::tar::Header;
|
||||
///
|
||||
/// let header = Header::new("test/1.txt").unwrap();
|
||||
/// let mode = header.mode().unwrap();
|
||||
/// assert_eq!(mode, 420);
|
||||
/// ```
|
||||
pub fn mode(&self) -> Result<u32, Error> {
|
||||
let mut s = String::new();
|
||||
for c in self.mode {
|
||||
if c != b'\0' {
|
||||
write!(s, "{c}")?;
|
||||
} else {
|
||||
if c == 0 {
|
||||
break;
|
||||
} else {
|
||||
write!(s, "{}", char::from(c))?;
|
||||
}
|
||||
}
|
||||
let mode = u32::from_str_radix(&s, 8)?;
|
||||
@ -145,10 +165,10 @@ impl Header {
|
||||
fn uid(&self) -> Result<u32, Error> {
|
||||
let mut s = String::new();
|
||||
for c in self.mode {
|
||||
if c != b'\0' {
|
||||
write!(s, "{c}")?;
|
||||
} else {
|
||||
if c == 0 {
|
||||
break;
|
||||
} else {
|
||||
write!(s, "{}", char::from(c))?;
|
||||
}
|
||||
}
|
||||
let uid = u32::from_str_radix(&s, 8)?;
|
||||
@ -158,10 +178,10 @@ impl Header {
|
||||
fn gid(&self) -> Result<u32, Error> {
|
||||
let mut s = String::new();
|
||||
for c in self.mode {
|
||||
if c != b'\0' {
|
||||
write!(s, "{c}")?;
|
||||
} else {
|
||||
if c == 0 {
|
||||
break;
|
||||
} else {
|
||||
write!(s, "{}", char::from(c))?;
|
||||
}
|
||||
}
|
||||
let gid = u32::from_str_radix(&s, 8)?;
|
||||
@ -171,10 +191,10 @@ impl Header {
|
||||
fn username(&self) -> Result<String, fmt::Error> {
|
||||
let mut s = String::new();
|
||||
for c in self.username {
|
||||
if c != b'\0' {
|
||||
write!(s, "{c}")?;
|
||||
} else {
|
||||
if c == 0 {
|
||||
break;
|
||||
} else {
|
||||
write!(s, "{}", char::from(c))?;
|
||||
}
|
||||
}
|
||||
Ok(s)
|
||||
@ -183,10 +203,10 @@ impl Header {
|
||||
fn groupname(&self) -> Result<String, fmt::Error> {
|
||||
let mut s = String::new();
|
||||
for c in self.groupname {
|
||||
if c != b'\0' {
|
||||
write!(s, "{c}")?;
|
||||
} else {
|
||||
if c == 0 {
|
||||
break;
|
||||
} else {
|
||||
write!(s, "{}", char::from(c))?;
|
||||
}
|
||||
}
|
||||
Ok(s)
|
||||
@ -205,25 +225,61 @@ impl Header {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn prefix(&self) -> Result<String, fmt::Error> {
|
||||
/// Gets the path to the file minus it's final component
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// use hpk_package::tar::Header;
|
||||
///
|
||||
/// let header = Header::new("test/1.txt").unwrap();
|
||||
/// let prefix = header.prefix().unwrap();
|
||||
/// assert_eq!(prefix.as_str(), "test");
|
||||
/// ```
|
||||
pub fn prefix(&self) -> Option<String> {
|
||||
let mut s = String::new();
|
||||
for c in self.file_prefix {
|
||||
if c != b'\0' {
|
||||
write!(s, "{c}")?;
|
||||
if c != 0 {
|
||||
write!(s, "{}", char::from(c)).ok()?;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(s)
|
||||
if s.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(s)
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the full file path to this archive member.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use hpk_package::tar::Header;
|
||||
/// use std::path::PathBuf;
|
||||
///
|
||||
/// let header = Header::new("test/1.txt").unwrap();
|
||||
/// let path = header.file_path().unwrap();
|
||||
/// assert_eq!(PathBuf::from("test/1.txt"), path);
|
||||
/// ```
|
||||
pub fn file_path(&self) -> Result<PathBuf, fmt::Error> {
|
||||
let mut path = match self.prefix() {
|
||||
Some(p) => PathBuf::from(&p),
|
||||
None => PathBuf::new(),
|
||||
};
|
||||
let name = self.filename()?;
|
||||
path.push(&name);
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
pub fn new(filename: &str) -> Result<Self, Error> {
|
||||
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 (filename, prefix) = {
|
||||
// Original tar has a maximum file name length of 100 bytes. The ustar
|
||||
// revision allows storing the path prefix separately, with 100 bytes
|
||||
// reserved for the file name and 150 bytes for the rest of the path.
|
||||
let path = PathBuf::from(&filename);
|
||||
let name = match path.file_name().and_then(|n| n.to_str()) {
|
||||
Some(n) => n.to_string(),
|
||||
@ -234,16 +290,8 @@ impl Header {
|
||||
)))
|
||||
}
|
||||
};
|
||||
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())))
|
||||
let dir = path.parent().map(|x| format!("{}", x.display()));
|
||||
(name, dir)
|
||||
};
|
||||
|
||||
/* Fill in metadata */
|
||||
@ -293,10 +341,10 @@ impl Header {
|
||||
owner: Option<Owner>,
|
||||
) -> Result<Self, Error> {
|
||||
let mut header = Header::default();
|
||||
let (filename, prefix) = if filename.len() < 100 {
|
||||
(filename.to_string(), None)
|
||||
} else {
|
||||
// Deal with file names longer than 100 bytes
|
||||
let (filename, prefix) = {
|
||||
// Original tar has a maximum file name length of 100 bytes. The ustar
|
||||
// revision allows storing the path prefix separately, with 100 bytes
|
||||
// reserved for the file name and 150 bytes for the rest of the path.
|
||||
let path = PathBuf::from(&filename);
|
||||
let name = match path.file_name().and_then(|n| n.to_str()) {
|
||||
Some(n) => n.to_string(),
|
||||
@ -307,16 +355,8 @@ impl Header {
|
||||
)))
|
||||
}
|
||||
};
|
||||
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())))
|
||||
let dir = path.parent().map(|x| format!("{}", x.display()));
|
||||
(name, dir)
|
||||
};
|
||||
header.fname[..filename.len()].copy_from_slice(filename.as_bytes());
|
||||
let mode = format!("{:07o}", meta.st_mode());
|
||||
@ -431,7 +471,7 @@ fn get_username_for_uid<'a>(uid: u32) -> Result<&'a str, std::str::Utf8Error> {
|
||||
user.to_str()
|
||||
}
|
||||
|
||||
pub fn get_groupname_for_gid<'a>(gid: u32) -> Result<&'a str, std::str::Utf8Error> {
|
||||
fn get_groupname_for_gid<'a>(gid: u32) -> Result<&'a str, std::str::Utf8Error> {
|
||||
let group = unsafe {
|
||||
let gr = libc::getgrgid(gid);
|
||||
let name = (*gr).gr_name;
|
||||
|
@ -165,4 +165,30 @@ mod test {
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rapid_num_eq() {
|
||||
let rapid = Rapid { major: 42, minor: 0 };
|
||||
assert_eq!(rapid, 42);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rapid_num_gt() {
|
||||
let rapid = Rapid { major: 1, minor: 42 };
|
||||
assert!(rapid > 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rapid_semver_eq() {
|
||||
let rapid = Rapid { major: 42, minor: 69 };
|
||||
let semver = SemVer { major: 42, minor: 69, patch: 0 };
|
||||
assert_eq!(rapid, semver);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rapid_semver_lt() {
|
||||
let rapid = Rapid { major: 42, minor: 69 };
|
||||
let semver = SemVer { major: 42, minor: 69, patch: 1 };
|
||||
assert!(rapid < semver);
|
||||
}
|
||||
}
|
||||
|
BIN
test/2.tar
BIN
test/2.tar
Binary file not shown.
Loading…
Reference in New Issue
Block a user