mirror of
https://github.com/rustic-rs/rustic.git
synced 2025-10-26 11:18:51 +00:00
Handle extended attributes
This commit is contained in:
parent
61dbe027cc
commit
e47708479c
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -1882,6 +1882,7 @@ dependencies = [
|
||||
"toml",
|
||||
"users",
|
||||
"walkdir",
|
||||
"xattr 1.0.0",
|
||||
"zstd",
|
||||
]
|
||||
|
||||
@ -2266,7 +2267,7 @@ checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6"
|
||||
dependencies = [
|
||||
"filetime",
|
||||
"libc",
|
||||
"xattr",
|
||||
"xattr 0.2.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2867,6 +2868,15 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xattr"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea263437ca03c1522846a4ddafbca2542d0ad5ed9b784909d4b27b76f62bc34a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.4.3"
|
||||
|
||||
@ -91,6 +91,7 @@ rhai = {version = "1.13", features = ["sync", "serde", "no_optimize", "no_module
|
||||
|
||||
[target.'cfg(not(windows))'.dependencies]
|
||||
users = "0.11"
|
||||
xattr = "1"
|
||||
|
||||
[dev-dependencies]
|
||||
rstest = "0.17"
|
||||
|
||||
@ -17,8 +17,8 @@ use serde_with::{serde_as, DisplayFromStr};
|
||||
#[cfg(not(windows))]
|
||||
use users::{Groups, Users, UsersCache};
|
||||
|
||||
use super::{node::Metadata, node::NodeType, Node, ReadSource};
|
||||
use super::{ReadSourceEntry, ReadSourceOpen};
|
||||
use super::node::{ExtendedAttribute, Metadata, NodeType};
|
||||
use super::{Node, ReadSource, ReadSourceEntry, ReadSourceOpen};
|
||||
|
||||
pub struct LocalSource {
|
||||
builder: WalkBuilder,
|
||||
@ -259,6 +259,7 @@ fn map_entry(
|
||||
inode,
|
||||
device_id,
|
||||
links,
|
||||
extended_attributes: Vec::new(),
|
||||
};
|
||||
|
||||
let node = if m.is_dir() {
|
||||
@ -322,6 +323,16 @@ fn map_entry(
|
||||
let device_id = if ignore_devid { 0 } else { m.dev() };
|
||||
let links = if m.is_dir() { 0 } else { m.nlink() };
|
||||
|
||||
let path = entry.path();
|
||||
let extended_attributes = xattr::list(path)?
|
||||
.map(|name| {
|
||||
Ok(ExtendedAttribute {
|
||||
name: name.to_string_lossy().to_string(),
|
||||
value: xattr::get(path, name)?.unwrap(),
|
||||
})
|
||||
})
|
||||
.collect::<Result<_>>()?;
|
||||
|
||||
let meta = Metadata {
|
||||
size,
|
||||
mtime,
|
||||
@ -335,6 +346,7 @@ fn map_entry(
|
||||
inode,
|
||||
device_id,
|
||||
links,
|
||||
extended_attributes,
|
||||
};
|
||||
let filetype = m.file_type();
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@ use crate::repository::parse_command;
|
||||
use super::mapper::map_mode_from_go;
|
||||
#[cfg(not(windows))]
|
||||
use super::node::NodeType;
|
||||
use super::node::{Metadata, Node};
|
||||
use super::node::{ExtendedAttribute, Metadata, Node};
|
||||
use super::{FileType, Id, ReadBackend, WriteBackend, ALL_FILE_TYPES};
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -324,6 +324,35 @@ impl LocalDestination {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn set_extended_attributes(
|
||||
&self,
|
||||
item: impl AsRef<Path>,
|
||||
extended_attributes: &[ExtendedAttribute],
|
||||
) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
pub fn set_extended_attributes(
|
||||
&self,
|
||||
item: impl AsRef<Path>,
|
||||
extended_attributes: &[ExtendedAttribute],
|
||||
) -> Result<()> {
|
||||
let filename = self.path(item);
|
||||
|
||||
for name in xattr::list(&filename)? {
|
||||
if let Err(err) = xattr::remove(&filename, &name) {
|
||||
warn!("error removing xattr on {filename:?}: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
for ExtendedAttribute { name, value } in extended_attributes {
|
||||
xattr::set(&filename, name, value)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// set_length sets the length of the given file. If it doesn't exist, create a new (empty) one with given length
|
||||
pub fn set_length(&self, item: impl AsRef<Path>, size: u64) -> Result<()> {
|
||||
let filename = self.path(item);
|
||||
|
||||
@ -14,6 +14,8 @@ use derive_getters::Getters;
|
||||
use derive_more::{Constructor, IsVariant};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_aux::prelude::*;
|
||||
use serde_with::base64::Base64;
|
||||
use serde_with::serde_as;
|
||||
|
||||
use crate::id::Id;
|
||||
|
||||
@ -68,6 +70,16 @@ pub struct Metadata {
|
||||
pub device_id: u64,
|
||||
pub size: u64,
|
||||
pub links: u64,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub extended_attributes: Vec<ExtendedAttribute>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct ExtendedAttribute {
|
||||
pub name: String,
|
||||
#[serde_as(as = "Base64")]
|
||||
pub value: Vec<u8>,
|
||||
}
|
||||
|
||||
fn is_default<T: Default + PartialEq>(t: &T) -> bool {
|
||||
|
||||
@ -453,6 +453,8 @@ fn set_metadata(dest: &LocalDestination, path: &PathBuf, node: &Node, opts: &Opt
|
||||
}
|
||||
dest.set_permission(path, node.meta())
|
||||
.unwrap_or_else(|_| warn!("restore {:?}: chmod failed.", path));
|
||||
dest.set_extended_attributes(path, &node.meta.extended_attributes)
|
||||
.unwrap_or_else(|_| warn!("restore {:?}: setting extended attributes failed.", path));
|
||||
dest.set_times(path, node.meta())
|
||||
.unwrap_or_else(|_| warn!("restore {:?}: setting file times failed.", path));
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user