src/backup/catalog.rs: impl read_dir() and lookup(), refactor common code
This commit is contained in:
parent
dc9596de45
commit
7d017123fd
@ -14,7 +14,7 @@ use crate::backup::file_formats::PROXMOX_CATALOG_FILE_MAGIC_1_0;
|
|||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Copy,Clone,PartialEq)]
|
#[derive(Copy,Clone,PartialEq)]
|
||||||
pub enum CatalogEntryType {
|
enum CatalogEntryType {
|
||||||
Directory = b'd',
|
Directory = b'd',
|
||||||
File = b'f',
|
File = b'f',
|
||||||
Symlink = b'l',
|
Symlink = b'l',
|
||||||
@ -49,12 +49,44 @@ impl fmt::Display for CatalogEntryType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DirEntry {
|
pub struct DirEntry {
|
||||||
name: Vec<u8>,
|
pub name: Vec<u8>,
|
||||||
attr: DirEntryAttribute,
|
pub attr: DirEntryAttribute,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum DirEntryAttribute {
|
impl DirEntry {
|
||||||
|
|
||||||
|
fn new(etype: CatalogEntryType, name: Vec<u8>, start: u64, size: u64, mtime:u64) -> Self {
|
||||||
|
match etype {
|
||||||
|
CatalogEntryType::Directory => {
|
||||||
|
DirEntry { name, attr: DirEntryAttribute::Directory { start } }
|
||||||
|
}
|
||||||
|
CatalogEntryType::File => {
|
||||||
|
DirEntry { name, attr: DirEntryAttribute::File { size, mtime } }
|
||||||
|
}
|
||||||
|
CatalogEntryType::Symlink => {
|
||||||
|
DirEntry { name, attr: DirEntryAttribute::Symlink }
|
||||||
|
}
|
||||||
|
CatalogEntryType::Hardlink => {
|
||||||
|
DirEntry { name, attr: DirEntryAttribute::Hardlink }
|
||||||
|
}
|
||||||
|
CatalogEntryType::BlockDevice => {
|
||||||
|
DirEntry { name, attr: DirEntryAttribute::BlockDevice }
|
||||||
|
}
|
||||||
|
CatalogEntryType::CharDevice => {
|
||||||
|
DirEntry { name, attr: DirEntryAttribute::CharDevice }
|
||||||
|
}
|
||||||
|
CatalogEntryType::Fifo => {
|
||||||
|
DirEntry { name, attr: DirEntryAttribute::Fifo }
|
||||||
|
}
|
||||||
|
CatalogEntryType::Socket => {
|
||||||
|
DirEntry { name, attr: DirEntryAttribute::Socket }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum DirEntryAttribute {
|
||||||
Directory { start: u64 },
|
Directory { start: u64 },
|
||||||
File { size: u64, mtime: u64 },
|
File { size: u64, mtime: u64 },
|
||||||
Symlink,
|
Symlink,
|
||||||
@ -355,15 +387,83 @@ impl <R: Read + Seek> CatalogReader<R> {
|
|||||||
self.dump_dir(std::path::Path::new("./"), start)
|
self.dump_dir(std::path::Path::new("./"), start)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the root DirEntry
|
||||||
|
pub fn root(&mut self) -> Result<DirEntry, Error> {
|
||||||
|
// Root dir is special
|
||||||
|
// mixme: verify magic
|
||||||
|
self.reader.seek(SeekFrom::End(-8))?;
|
||||||
|
let start = unsafe { self.reader.read_le_value::<u64>()? };
|
||||||
|
Ok(DirEntry { name: b"".to_vec(), attr: DirEntryAttribute::Directory { start } })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read all directory entries
|
||||||
|
pub fn read_dir(
|
||||||
|
&mut self,
|
||||||
|
parent: &DirEntry,
|
||||||
|
) -> Result<Vec<DirEntry>, Error> {
|
||||||
|
|
||||||
|
let start = match parent.attr {
|
||||||
|
DirEntryAttribute::Directory { start } => start,
|
||||||
|
_ => bail!("parent is not a directory - internal error"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let data = self.read_raw_dirinfo_block(start)?;
|
||||||
|
|
||||||
|
let mut entry_list = Vec::new();
|
||||||
|
|
||||||
|
DirInfo::parse(&data, |etype, name, offset, size, mtime| {
|
||||||
|
let entry = DirEntry::new(etype, name.to_vec(), offset, size, mtime);
|
||||||
|
entry_list.push(entry);
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(entry_list)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Lockup a DirEntry inside a parent directory
|
||||||
|
pub fn lookup(
|
||||||
|
&mut self,
|
||||||
|
parent: &DirEntry,
|
||||||
|
filename: &[u8],
|
||||||
|
) -> Result<DirEntry, Error> {
|
||||||
|
|
||||||
|
let start = match parent.attr {
|
||||||
|
DirEntryAttribute::Directory { start } => start,
|
||||||
|
_ => bail!("parent is not a directory - internal error"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let data = self.read_raw_dirinfo_block(start)?;
|
||||||
|
|
||||||
|
let mut item = None;
|
||||||
|
DirInfo::parse(&data, |etype, name, offset, size, mtime| {
|
||||||
|
if name != filename {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let entry = DirEntry::new(etype, name.to_vec(), offset, size, mtime);
|
||||||
|
item = Some(entry);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
match item {
|
||||||
|
None => bail!("no such file"),
|
||||||
|
Some(entry) => Ok(entry),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read the raw directory info block from current reader position.
|
||||||
|
fn read_raw_dirinfo_block(&mut self, start: u64) -> Result<Vec<u8>, Error> {
|
||||||
|
self.reader.seek(SeekFrom::Start(start))?;
|
||||||
|
let size = catalog_decode_u64(&mut self.reader)?;
|
||||||
|
if size < 1 { bail!("got small directory size {}", size) };
|
||||||
|
let data = self.reader.read_exact_allocated(size as usize)?;
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn dump_dir(&mut self, prefix: &std::path::Path, start: u64) -> Result<(), Error> {
|
pub fn dump_dir(&mut self, prefix: &std::path::Path, start: u64) -> Result<(), Error> {
|
||||||
|
|
||||||
self.reader.seek(SeekFrom::Start(start))?;
|
let data = self.read_raw_dirinfo_block(start)?;
|
||||||
|
|
||||||
let size = catalog_decode_u64(&mut self.reader)?;
|
|
||||||
|
|
||||||
if size < 1 { bail!("got small directory size {}", size) };
|
|
||||||
|
|
||||||
let data = self.reader.read_exact_allocated(size as usize)?;
|
|
||||||
|
|
||||||
DirInfo::parse(&data, |etype, name, offset, size, mtime| {
|
DirInfo::parse(&data, |etype, name, offset, size, mtime| {
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user