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 {
|
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> {
|
pub fn filename(&self) -> Result<String, fmt::Error> {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
for c in self.fname {
|
for c in self.fname {
|
||||||
if c != b'\0' {
|
if c == 0 {
|
||||||
write!(s, "{c}")?;
|
|
||||||
} else {
|
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
write!(s, "{}", char::from(c))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(s)
|
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> {
|
pub fn mode(&self) -> Result<u32, Error> {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
for c in self.mode {
|
for c in self.mode {
|
||||||
if c != b'\0' {
|
if c == 0 {
|
||||||
write!(s, "{c}")?;
|
|
||||||
} else {
|
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
write!(s, "{}", char::from(c))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mode = u32::from_str_radix(&s, 8)?;
|
let mode = u32::from_str_radix(&s, 8)?;
|
||||||
@ -145,10 +165,10 @@ impl Header {
|
|||||||
fn uid(&self) -> Result<u32, Error> {
|
fn uid(&self) -> Result<u32, Error> {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
for c in self.mode {
|
for c in self.mode {
|
||||||
if c != b'\0' {
|
if c == 0 {
|
||||||
write!(s, "{c}")?;
|
|
||||||
} else {
|
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
write!(s, "{}", char::from(c))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let uid = u32::from_str_radix(&s, 8)?;
|
let uid = u32::from_str_radix(&s, 8)?;
|
||||||
@ -158,10 +178,10 @@ impl Header {
|
|||||||
fn gid(&self) -> Result<u32, Error> {
|
fn gid(&self) -> Result<u32, Error> {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
for c in self.mode {
|
for c in self.mode {
|
||||||
if c != b'\0' {
|
if c == 0 {
|
||||||
write!(s, "{c}")?;
|
|
||||||
} else {
|
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
write!(s, "{}", char::from(c))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let gid = u32::from_str_radix(&s, 8)?;
|
let gid = u32::from_str_radix(&s, 8)?;
|
||||||
@ -171,10 +191,10 @@ impl Header {
|
|||||||
fn username(&self) -> Result<String, fmt::Error> {
|
fn username(&self) -> Result<String, fmt::Error> {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
for c in self.username {
|
for c in self.username {
|
||||||
if c != b'\0' {
|
if c == 0 {
|
||||||
write!(s, "{c}")?;
|
|
||||||
} else {
|
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
write!(s, "{}", char::from(c))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(s)
|
Ok(s)
|
||||||
@ -183,10 +203,10 @@ impl Header {
|
|||||||
fn groupname(&self) -> Result<String, fmt::Error> {
|
fn groupname(&self) -> Result<String, fmt::Error> {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
for c in self.groupname {
|
for c in self.groupname {
|
||||||
if c != b'\0' {
|
if c == 0 {
|
||||||
write!(s, "{c}")?;
|
|
||||||
} else {
|
|
||||||
break;
|
break;
|
||||||
|
} else {
|
||||||
|
write!(s, "{}", char::from(c))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(s)
|
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();
|
let mut s = String::new();
|
||||||
for c in self.file_prefix {
|
for c in self.file_prefix {
|
||||||
if c != b'\0' {
|
if c != 0 {
|
||||||
write!(s, "{c}")?;
|
write!(s, "{}", char::from(c)).ok()?;
|
||||||
} else {
|
} else {
|
||||||
break;
|
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> {
|
pub fn new(filename: &str) -> Result<Self, Error> {
|
||||||
let mut header = Header::default();
|
let mut header = Header::default();
|
||||||
let meta = fs::symlink_metadata(filename)?;
|
let meta = fs::symlink_metadata(filename)?;
|
||||||
let (filename, prefix) = if filename.len() < 100 {
|
let (filename, prefix) = {
|
||||||
(filename.to_string(), None)
|
// Original tar has a maximum file name length of 100 bytes. The ustar
|
||||||
} else {
|
// revision allows storing the path prefix separately, with 100 bytes
|
||||||
// Deal with file names longer than 100 bytes
|
// reserved for the file name and 150 bytes for the rest of the path.
|
||||||
let path = PathBuf::from(&filename);
|
let path = PathBuf::from(&filename);
|
||||||
let name = match path.file_name().and_then(|n| n.to_str()) {
|
let name = match path.file_name().and_then(|n| n.to_str()) {
|
||||||
Some(n) => n.to_string(),
|
Some(n) => n.to_string(),
|
||||||
@ -234,16 +290,8 @@ impl Header {
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let dir = match path.parent() {
|
let dir = path.parent().map(|x| format!("{}", x.display()));
|
||||||
Some(d) => d,
|
(name, dir)
|
||||||
None => {
|
|
||||||
return Err(Error::Io(io::Error::new(
|
|
||||||
io::ErrorKind::Other,
|
|
||||||
"Cannot get path prefix",
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
(name, Some(format!("{}", dir.display())))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Fill in metadata */
|
/* Fill in metadata */
|
||||||
@ -293,10 +341,10 @@ impl Header {
|
|||||||
owner: Option<Owner>,
|
owner: Option<Owner>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let mut header = Header::default();
|
let mut header = Header::default();
|
||||||
let (filename, prefix) = if filename.len() < 100 {
|
let (filename, prefix) = {
|
||||||
(filename.to_string(), None)
|
// Original tar has a maximum file name length of 100 bytes. The ustar
|
||||||
} else {
|
// revision allows storing the path prefix separately, with 100 bytes
|
||||||
// Deal with file names longer than 100 bytes
|
// reserved for the file name and 150 bytes for the rest of the path.
|
||||||
let path = PathBuf::from(&filename);
|
let path = PathBuf::from(&filename);
|
||||||
let name = match path.file_name().and_then(|n| n.to_str()) {
|
let name = match path.file_name().and_then(|n| n.to_str()) {
|
||||||
Some(n) => n.to_string(),
|
Some(n) => n.to_string(),
|
||||||
@ -307,16 +355,8 @@ impl Header {
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let dir = match path.parent() {
|
let dir = path.parent().map(|x| format!("{}", x.display()));
|
||||||
Some(d) => d,
|
(name, dir)
|
||||||
None => {
|
|
||||||
return Err(Error::Io(io::Error::new(
|
|
||||||
io::ErrorKind::Other,
|
|
||||||
"Cannot get path prefix",
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
(name, Some(format!("{}", dir.display())))
|
|
||||||
};
|
};
|
||||||
header.fname[..filename.len()].copy_from_slice(filename.as_bytes());
|
header.fname[..filename.len()].copy_from_slice(filename.as_bytes());
|
||||||
let mode = format!("{:07o}", meta.st_mode());
|
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()
|
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 group = unsafe {
|
||||||
let gr = libc::getgrgid(gid);
|
let gr = libc::getgrgid(gid);
|
||||||
let name = (*gr).gr_name;
|
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