Add test for loading and storing symlink nodes and fix multiple logic errors
This commit is contained in:
parent
e226f1982d
commit
455a2d36f9
@ -4,7 +4,7 @@ use {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub(crate) enum Flag {
|
pub(crate) enum Flag {
|
||||||
Normal = 0,
|
Normal = 0,
|
||||||
HardLink = 1,
|
HardLink = 1,
|
||||||
@ -52,7 +52,15 @@ impl From<&FileType> for Flag {
|
|||||||
impl Flag {
|
impl Flag {
|
||||||
pub(crate) fn append_mode(&self, mode: u16) -> u16 {
|
pub(crate) fn append_mode(&self, mode: u16) -> u16 {
|
||||||
let mask: u16 = u16::from(*self as u8) << 13;
|
let mask: u16 = u16::from(*self as u8) << 13;
|
||||||
mode & mask
|
mode | mask
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn extract_from_raw(raw: u16) -> Result<(Self, u16), Error> {
|
||||||
|
let mask: u16 = 0b111 << 13;
|
||||||
|
let mode = raw & 0o777;
|
||||||
|
let flag: u8 = ((raw & mask) >> 13).try_into()?;
|
||||||
|
let flag: Self = flag.try_into()?;
|
||||||
|
Ok((flag, mode))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +98,7 @@ impl FileType {
|
|||||||
let len = u16::from_le_bytes(len);
|
let len = u16::from_le_bytes(len);
|
||||||
let mut buf = Vec::with_capacity(len.into());
|
let mut buf = Vec::with_capacity(len.into());
|
||||||
let mut handle = reader.take(len.into());
|
let mut handle = reader.take(len.into());
|
||||||
handle.read_exact(&mut buf)?;
|
handle.read_to_end(&mut buf)?;
|
||||||
let s = String::from_utf8(buf)?;
|
let s = String::from_utf8(buf)?;
|
||||||
Ok(Self::HardLink(s))
|
Ok(Self::HardLink(s))
|
||||||
}
|
}
|
||||||
@ -100,7 +108,7 @@ impl FileType {
|
|||||||
let len = u16::from_le_bytes(len);
|
let len = u16::from_le_bytes(len);
|
||||||
let mut buf = Vec::with_capacity(len.into());
|
let mut buf = Vec::with_capacity(len.into());
|
||||||
let mut handle = reader.take(len.into());
|
let mut handle = reader.take(len.into());
|
||||||
handle.read_exact(&mut buf)?;
|
handle.read_to_end(&mut buf)?;
|
||||||
let s = String::from_utf8(buf)?;
|
let s = String::from_utf8(buf)?;
|
||||||
Ok(Self::SoftLink(s))
|
Ok(Self::SoftLink(s))
|
||||||
}
|
}
|
||||||
@ -122,7 +130,7 @@ impl FileType {
|
|||||||
match self {
|
match self {
|
||||||
Self::Normal(f) => f.write(writer)?,
|
Self::Normal(f) => f.write(writer)?,
|
||||||
Self::HardLink(s) | Self::SoftLink(s) => {
|
Self::HardLink(s) | Self::SoftLink(s) => {
|
||||||
let len = s.len() as u64;
|
let len = s.len() as u16;
|
||||||
writer.write_all(&len.to_le_bytes())?;
|
writer.write_all(&len.to_le_bytes())?;
|
||||||
writer.write_all(s.as_bytes())?;
|
writer.write_all(s.as_bytes())?;
|
||||||
}
|
}
|
||||||
@ -132,3 +140,28 @@ impl FileType {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn manipulate_mode_softlink() {
|
||||||
|
let mode: u16 = 0o644;
|
||||||
|
let flag = Flag::SoftLink;
|
||||||
|
let raw = flag.append_mode(mode);
|
||||||
|
let (f, m) = Flag::extract_from_raw(raw).unwrap();
|
||||||
|
assert_eq!(m, mode);
|
||||||
|
assert_eq!(f, flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn manipulate_mode_normal() {
|
||||||
|
let mode: u16 = 0o755;
|
||||||
|
let flag = Flag::Normal;
|
||||||
|
let raw = flag.append_mode(mode);
|
||||||
|
let (f, m) = Flag::extract_from_raw(raw).unwrap();
|
||||||
|
assert_eq!(m, mode);
|
||||||
|
assert_eq!(f, flag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
45
src/node.rs
45
src/node.rs
@ -85,10 +85,7 @@ impl Node {
|
|||||||
let mtime: [u8; 8] = buf[8..16].try_into()?;
|
let mtime: [u8; 8] = buf[8..16].try_into()?;
|
||||||
let raw_mode: [u8; 2] = buf[16..18].try_into()?;
|
let raw_mode: [u8; 2] = buf[16..18].try_into()?;
|
||||||
let raw_mode = u16::from_le_bytes(raw_mode);
|
let raw_mode = u16::from_le_bytes(raw_mode);
|
||||||
let mask: u16 = 0b111 << 13;
|
let (flag, mode) = Flag::extract_from_raw(raw_mode)?;
|
||||||
let mode = raw_mode & mask;
|
|
||||||
let flag: u8 = ((raw_mode & !mask) >> 13).try_into()?;
|
|
||||||
let flag: Flag = flag.try_into()?;
|
|
||||||
let filetype = FileType::read(reader, flag)?;
|
let filetype = FileType::read(reader, flag)?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
name: String::from_utf8(name)?,
|
name: String::from_utf8(name)?,
|
||||||
@ -203,12 +200,13 @@ impl Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let mode = Flag::from(&filetype).append_mode(u16::try_from(mode & 0o7777)?);
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
name,
|
name,
|
||||||
uid,
|
uid,
|
||||||
gid,
|
gid,
|
||||||
mtime,
|
mtime,
|
||||||
mode: (mode & !(0o111 << 13)).try_into()?,
|
mode,
|
||||||
filetype,
|
filetype,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -405,12 +403,22 @@ mod tests {
|
|||||||
let mut writer = std::io::BufWriter::new(fd);
|
let mut writer = std::io::BufWriter::new(fd);
|
||||||
let links = Mutex::new(HashMap::new());
|
let links = Mutex::new(HashMap::new());
|
||||||
let node = Node::from_path("test/li.txt", Algorithm::Sha1, &links).unwrap();
|
let node = Node::from_path("test/li.txt", Algorithm::Sha1, &links).unwrap();
|
||||||
|
let FileType::Normal(_) = node.filetype else {
|
||||||
|
eprintln!("Created wrong filetype: {:?}", node.filetype);
|
||||||
|
panic!();
|
||||||
|
};
|
||||||
node.write(&mut writer).unwrap();
|
node.write(&mut writer).unwrap();
|
||||||
}
|
}
|
||||||
|
let meta = fs::metadata("test/li.txt").unwrap();
|
||||||
let fd = std::fs::File::open("test/li.node").unwrap();
|
let fd = std::fs::File::open("test/li.node").unwrap();
|
||||||
let mut reader = BufReader::new(fd);
|
let mut reader = BufReader::new(fd);
|
||||||
let node = Node::read(&mut reader).unwrap();
|
let node = Node::read(&mut reader).unwrap();
|
||||||
|
assert_eq!(meta.mode() & 0o777, node.mode as u32);
|
||||||
|
assert_eq!(meta.uid(), node.uid);
|
||||||
|
assert_eq!(meta.gid(), node.gid);
|
||||||
|
assert_eq!(meta.mtime(), node.mtime as i64);
|
||||||
let FileType::Normal(f) = node.filetype else {
|
let FileType::Normal(f) = node.filetype else {
|
||||||
|
eprintln!("Read incorrect filetype: {:?}", node.filetype);
|
||||||
panic!()
|
panic!()
|
||||||
};
|
};
|
||||||
let Checksum::Sha1(sum) = f.checksum else {
|
let Checksum::Sha1(sum) = f.checksum else {
|
||||||
@ -424,6 +432,33 @@ mod tests {
|
|||||||
assert_eq!(LI, f.data);
|
assert_eq!(LI, f.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_store_symlink() {
|
||||||
|
{
|
||||||
|
let _res = remove_file("test/lilnk.txt");
|
||||||
|
symlink("li.txt", "test/lilnk.txt").unwrap();
|
||||||
|
let _res = remove_file("test/lilnk.node");
|
||||||
|
let fd = std::fs::File::create("test/lilnk.node").unwrap();
|
||||||
|
let mut writer = std::io::BufWriter::new(fd);
|
||||||
|
let links = Mutex::new(HashMap::new());
|
||||||
|
let node = Node::from_path("test/lilnk.txt", Algorithm::Sha1, &links).unwrap();
|
||||||
|
let FileType::SoftLink(ref tgt) = node.filetype else {
|
||||||
|
eprintln!("Created wrong filetype: {:?}", node.filetype);
|
||||||
|
panic!();
|
||||||
|
};
|
||||||
|
assert_eq!(tgt, "li.txt");
|
||||||
|
node.write(&mut writer).unwrap();
|
||||||
|
}
|
||||||
|
let fd = std::fs::File::open("test/lilnk.node").unwrap();
|
||||||
|
let mut reader = BufReader::new(fd);
|
||||||
|
let node = Node::read(&mut reader).unwrap();
|
||||||
|
let FileType::SoftLink(ref tgt) = node.filetype else {
|
||||||
|
eprintln!("Read incorrect filetype: {:?}", node.filetype);
|
||||||
|
panic!();
|
||||||
|
};
|
||||||
|
assert_eq!(tgt, "li.txt");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn extract_file() {
|
fn extract_file() {
|
||||||
let links = Mutex::new(HashMap::new());
|
let links = Mutex::new(HashMap::new());
|
||||||
|
Loading…
Reference in New Issue
Block a user