diff --git a/src/archiver.rs b/src/archiver.rs index b4e86c2..6239a8e 100644 --- a/src/archiver.rs +++ b/src/archiver.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use anyhow::{anyhow, Result}; use crate::backend::DecryptWriteBackend; -use crate::blob::{BlobType, Node, NodeType, Packer, Tree}; +use crate::blob::{BlobType, Metadata, Node, NodeType, Packer, Tree}; use crate::chunker::ChunkIter; use crate::crypto::hash; use crate::index::{Indexer, ReadIndex}; @@ -71,7 +71,8 @@ impl Archiver { self.stack.push((node, tree)); return Ok(()); } else { - self.stack.push((Node::new_dir(p.to_os_string()), tree)); + self.stack + .push((Node::new_dir(p.to_os_string(), Metadata::default()), tree)); } println!("add tree {:?}, path: {:?}", p, self.path); diff --git a/src/backend/node.rs b/src/backend/node.rs index 7c240d5..edc9523 100644 --- a/src/backend/node.rs +++ b/src/backend/node.rs @@ -1,5 +1,6 @@ use std::ffi::OsString; use std::fmt::Debug; +use std::path::PathBuf; use chrono::{DateTime, Local}; use derive_getters::Getters; @@ -30,7 +31,7 @@ pub enum NodeType { Device { device: u64 }, } -#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, Getters)] +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, Constructor, Getters)] pub struct Metadata { #[serde(default)] size: u64, @@ -56,23 +57,35 @@ pub struct Metadata { } impl Node { - pub fn new_file(name: OsString) -> Self { + pub fn new_file(name: OsString, meta: Metadata) -> Self { Self { name: name.to_str().expect("no unicode").to_string(), node_type: NodeType::File, content: Vec::new(), subtree: None, - meta: Metadata::default(), + meta, } } - pub fn new_dir(name: OsString) -> Self { + pub fn new_dir(name: OsString, meta: Metadata) -> Self { Self { name: name.to_str().expect("no unicode").to_string(), node_type: NodeType::Dir, content: Vec::new(), subtree: None, - meta: Metadata::default(), + meta, + } + } + + pub fn new_symlink(name: OsString, target: PathBuf, meta: Metadata) -> Self { + Self { + name: name.to_str().expect("no unicode").to_string(), + node_type: NodeType::Symlink { + linktarget: target.to_str().expect("no unicode").to_string(), + }, + content: Vec::new(), + subtree: None, + meta, } } diff --git a/src/commands/backup.rs b/src/commands/backup.rs index afca9d8..e7b6e90 100644 --- a/src/commands/backup.rs +++ b/src/commands/backup.rs @@ -1,5 +1,6 @@ -use std::fs::File; +use std::fs::{read_link, File}; use std::io::BufReader; +use std::os::unix::fs::MetadataExt; use std::path::PathBuf; use anyhow::Result; @@ -9,7 +10,7 @@ use path_absolutize::*; use crate::archiver::Archiver; use crate::backend::DecryptFullBackend; -use crate::blob::Node; +use crate::blob::{Metadata, Node}; use crate::index::IndexBackend; use crate::repo::ConfigFile; @@ -45,14 +46,31 @@ fn backup_file(backup_path: PathBuf, poly: &u64, be: &impl DecryptFullBackend) - for entry in wb.build() { let entry = entry?; let name = entry.file_name().to_os_string(); - let file_type = entry.file_type().unwrap(); - let (node, r) = if file_type.is_dir() { - let f = File::open(&entry.path())?; - (Node::new_dir(name), Some(BufReader::new(f))) - } else { - (Node::new_file(name), None) - }; + let m = entry.metadata()?; + let meta = Metadata::new( + m.len(), + m.modified().ok().map(|t| t.into()), + m.accessed().ok().map(|t| t.into()), + m.created().ok().map(|t| t.into()), + m.mode(), + m.uid(), + m.gid(), + "".to_string(), + "".to_string(), + m.ino(), + m.dev(), + m.nlink(), + ); + let (node, r) = if m.is_dir() { + (Node::new_dir(name, meta), None) + } else if m.is_symlink() { + let target = read_link(entry.path())?; + (Node::new_symlink(name, target, meta), None) + } else { + let f = File::open(&entry.path())?; + (Node::new_file(name, meta), Some(BufReader::new(f))) + }; archiver.add_entry(entry.path(), node, r)?; } archiver.finalize_snapshot(backup_path)?;