Handle extended attributes

This commit is contained in:
Alexander Weiss 2023-03-23 13:57:09 +01:00
parent 61dbe027cc
commit e47708479c
6 changed files with 70 additions and 4 deletions

12
Cargo.lock generated
View File

@ -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"

View File

@ -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"

View File

@ -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();

View File

@ -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);

View File

@ -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 {

View File

@ -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));
}