update to proxmox-sys 0.2 crate
- imported pbs-api-types/src/common_regex.rs from old proxmox crate - use hex crate to generate/parse hex digest - remove all reference to proxmox crate (use proxmox-sys and proxmox-serde instead) Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
This commit is contained in:
parent
bd00ff10e4
commit
25877d05ac
11
Cargo.toml
11
Cargo.toml
|
@ -94,8 +94,7 @@ zstd = { version = "0.6", features = [ "bindgen" ] }
|
||||||
pathpatterns = "0.1.2"
|
pathpatterns = "0.1.2"
|
||||||
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
|
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
|
||||||
|
|
||||||
proxmox = { version = "0.15.3", features = [ "sortable-macro" ] }
|
proxmox-http = { version = "0.6", features = [ "client", "http-helpers", "websocket" ] }
|
||||||
proxmox-http = { version = "0.5.4", features = [ "client", "http-helpers", "websocket" ] }
|
|
||||||
proxmox-io = "1"
|
proxmox-io = "1"
|
||||||
proxmox-lang = "1"
|
proxmox-lang = "1"
|
||||||
proxmox-router = { version = "1.1", features = [ "cli" ] }
|
proxmox-router = { version = "1.1", features = [ "cli" ] }
|
||||||
|
@ -104,12 +103,14 @@ proxmox-section-config = "1"
|
||||||
proxmox-tfa = { version = "1.3", features = [ "api", "api-types" ] }
|
proxmox-tfa = { version = "1.3", features = [ "api", "api-types" ] }
|
||||||
proxmox-time = "1"
|
proxmox-time = "1"
|
||||||
proxmox-uuid = "1"
|
proxmox-uuid = "1"
|
||||||
proxmox-shared-memory = "0.1.1"
|
proxmox-serde = "0.1"
|
||||||
proxmox-sys = "0.1.2"
|
proxmox-shared-memory = "0.2"
|
||||||
|
proxmox-sys = { version = "0.2", features = [ "sortable-macro" ] }
|
||||||
|
|
||||||
|
|
||||||
proxmox-acme-rs = "0.3"
|
proxmox-acme-rs = "0.3"
|
||||||
proxmox-apt = "0.8.0"
|
proxmox-apt = "0.8.0"
|
||||||
proxmox-async = "0.2"
|
proxmox-async = "0.3"
|
||||||
proxmox-openid = "0.9.0"
|
proxmox-openid = "0.9.0"
|
||||||
|
|
||||||
pbs-api-types = { path = "pbs-api-types" }
|
pbs-api-types = { path = "pbs-api-types" }
|
||||||
|
|
|
@ -40,18 +40,15 @@ Build-Depends: debhelper (>= 12),
|
||||||
librust-pathpatterns-0.1+default-dev (>= 0.1.2-~~),
|
librust-pathpatterns-0.1+default-dev (>= 0.1.2-~~),
|
||||||
librust-percent-encoding-2+default-dev (>= 2.1-~~),
|
librust-percent-encoding-2+default-dev (>= 2.1-~~),
|
||||||
librust-pin-project-lite-0.2+default-dev,
|
librust-pin-project-lite-0.2+default-dev,
|
||||||
librust-proxmox-0.15+default-dev (>= 0.15.3-~~),
|
|
||||||
librust-proxmox-0.15+sortable-macro-dev (>= 0.15.3-~~),
|
|
||||||
librust-proxmox-0.15+tokio-dev (>= 0.15.3-~~),
|
|
||||||
librust-proxmox-acme-rs-0.3+default-dev,
|
librust-proxmox-acme-rs-0.3+default-dev,
|
||||||
librust-proxmox-apt-0.8+default-dev,
|
librust-proxmox-apt-0.8+default-dev,
|
||||||
librust-proxmox-async-0.2+default-dev,
|
librust-proxmox-async-0.3+default-dev,
|
||||||
librust-proxmox-borrow-1+default-dev,
|
librust-proxmox-borrow-1+default-dev,
|
||||||
librust-proxmox-fuse-0.1+default-dev (>= 0.1.1-~~),
|
librust-proxmox-fuse-0.1+default-dev (>= 0.1.1-~~),
|
||||||
librust-proxmox-http-0.5+client-dev (>= 0.5.4-~~),
|
librust-proxmox-http-0.6+client-dev,
|
||||||
librust-proxmox-http-0.5+default-dev (>= 0.5.4-~~),
|
librust-proxmox-http-0.6+default-dev,
|
||||||
librust-proxmox-http-0.5+http-helpers-dev (>= 0.5.4-~~),
|
librust-proxmox-http-0.6+http-helpers-dev,
|
||||||
librust-proxmox-http-0.5+websocket-dev (>= 0.5.4-~~),
|
librust-proxmox-http-0.6+websocket-dev,
|
||||||
librust-proxmox-io-1+default-dev,
|
librust-proxmox-io-1+default-dev,
|
||||||
librust-proxmox-io-1+tokio-dev,
|
librust-proxmox-io-1+tokio-dev,
|
||||||
librust-proxmox-lang-1+default-dev,
|
librust-proxmox-lang-1+default-dev,
|
||||||
|
@ -62,8 +59,9 @@ Build-Depends: debhelper (>= 12),
|
||||||
librust-proxmox-schema-1+default-dev (>= 1.0.1-~~),
|
librust-proxmox-schema-1+default-dev (>= 1.0.1-~~),
|
||||||
librust-proxmox-schema-1+upid-api-impl-dev (>= 1.0.1-~~),
|
librust-proxmox-schema-1+upid-api-impl-dev (>= 1.0.1-~~),
|
||||||
librust-proxmox-section-config-1+default-dev,
|
librust-proxmox-section-config-1+default-dev,
|
||||||
librust-proxmox-shared-memory-0.1+default-dev (>= 0.1.1-~~),
|
librust-proxmox-shared-memory-0.2+default-dev,
|
||||||
librust-proxmox-sys-0.1+default-dev (>= 0.1.2-~~),
|
librust-proxmox-sys-0.2+default-dev,
|
||||||
|
librust-proxmox-sys-0.2+sortable-macro-dev,
|
||||||
librust-proxmox-tfa-1+api-dev (>= 1.3-~~),
|
librust-proxmox-tfa-1+api-dev (>= 1.3-~~),
|
||||||
librust-proxmox-tfa-1+api-types-dev (>= 1.3-~~),
|
librust-proxmox-tfa-1+api-types-dev (>= 1.3-~~),
|
||||||
librust-proxmox-tfa-1+default-dev (>= 1.3-~~),
|
librust-proxmox-tfa-1+default-dev (>= 1.3-~~),
|
||||||
|
|
|
@ -27,7 +27,7 @@ fn rate_test(name: &str, bench: &dyn Fn() -> usize) {
|
||||||
|
|
||||||
fn main() -> Result<(), Error> {
|
fn main() -> Result<(), Error> {
|
||||||
|
|
||||||
let input = proxmox::sys::linux::random_data(1024*1024)?;
|
let input = proxmox_sys::linux::random_data(1024*1024)?;
|
||||||
|
|
||||||
rate_test("crc32", &|| {
|
rate_test("crc32", &|| {
|
||||||
let mut crchasher = crc32fast::Hasher::new();
|
let mut crchasher = crc32fast::Hasher::new();
|
||||||
|
@ -46,9 +46,9 @@ fn main() -> Result<(), Error> {
|
||||||
input.len()
|
input.len()
|
||||||
});
|
});
|
||||||
|
|
||||||
let key = proxmox::sys::linux::random_data(32)?;
|
let key = proxmox_sys::linux::random_data(32)?;
|
||||||
|
|
||||||
let iv = proxmox::sys::linux::random_data(16)?;
|
let iv = proxmox_sys::linux::random_data(16)?;
|
||||||
|
|
||||||
let cipher = openssl::symm::Cipher::aes_256_gcm();
|
let cipher = openssl::symm::Cipher::aes_256_gcm();
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,10 @@ openssl = "0.10"
|
||||||
regex = "1.2"
|
regex = "1.2"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|
||||||
proxmox = "0.15.3"
|
|
||||||
proxmox-lang = "1.0.0"
|
proxmox-lang = "1.0.0"
|
||||||
proxmox-schema = { version = "1.0.1", features = [ "api-macro" ] }
|
proxmox-schema = { version = "1.0.1", features = [ "api-macro" ] }
|
||||||
|
proxmox-serde = "0.1"
|
||||||
proxmox-time = "1.1"
|
proxmox-time = "1.1"
|
||||||
proxmox-uuid = { version = "1.0.0", features = [ "serde" ] }
|
proxmox-uuid = { version = "1.0.0", features = [ "serde" ] }
|
||||||
|
|
||||||
|
proxmox-sys = "0.2" # only needed foör nodename()??
|
|
@ -0,0 +1,78 @@
|
||||||
|
//! Predefined Regular Expressions
|
||||||
|
//!
|
||||||
|
//! This is a collection of useful regular expressions
|
||||||
|
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! IPV4OCTET { () => (r"(?:25[0-5]|(?:2[0-4]|1[0-9]|[1-9])?[0-9])") }
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! IPV6H16 { () => (r"(?:[0-9a-fA-F]{1,4})") }
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! IPV6LS32 { () => (concat!(r"(?:(?:", IPV4RE!(), "|", IPV6H16!(), ":", IPV6H16!(), "))" )) }
|
||||||
|
|
||||||
|
/// Returns the regular expression string to match IPv4 addresses
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! IPV4RE { () => (concat!(r"(?:(?:", IPV4OCTET!(), r"\.){3}", IPV4OCTET!(), ")")) }
|
||||||
|
|
||||||
|
/// Returns the regular expression string to match IPv6 addresses
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! IPV6RE { () => (concat!(r"(?:",
|
||||||
|
r"(?:(?:", r"(?:", IPV6H16!(), r":){6})", IPV6LS32!(), r")|",
|
||||||
|
r"(?:(?:", r"::(?:", IPV6H16!(), r":){5})", IPV6LS32!(), r")|",
|
||||||
|
r"(?:(?:(?:", IPV6H16!(), r")?::(?:", IPV6H16!(), r":){4})", IPV6LS32!(), r")|",
|
||||||
|
r"(?:(?:(?:(?:", IPV6H16!(), r":){0,1}", IPV6H16!(), r")?::(?:", IPV6H16!(), r":){3})", IPV6LS32!(), r")|",
|
||||||
|
r"(?:(?:(?:(?:", IPV6H16!(), r":){0,2}", IPV6H16!(), r")?::(?:", IPV6H16!(), r":){2})", IPV6LS32!(), r")|",
|
||||||
|
r"(?:(?:(?:(?:", IPV6H16!(), r":){0,3}", IPV6H16!(), r")?::(?:", IPV6H16!(), r":){1})", IPV6LS32!(), r")|",
|
||||||
|
r"(?:(?:(?:(?:", IPV6H16!(), r":){0,4}", IPV6H16!(), r")?::", ")", IPV6LS32!(), r")|",
|
||||||
|
r"(?:(?:(?:(?:", IPV6H16!(), r":){0,5}", IPV6H16!(), r")?::", ")", IPV6H16!(), r")|",
|
||||||
|
r"(?:(?:(?:(?:", IPV6H16!(), r":){0,6}", IPV6H16!(), r")?::", ")))"))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the regular expression string to match IP addresses (v4 or v6)
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! IPRE { () => (concat!(r"(?:", IPV4RE!(), "|", IPV6RE!(), ")")) }
|
||||||
|
|
||||||
|
/// Regular expression string to match IP addresses where IPv6 addresses require brackets around
|
||||||
|
/// them, while for IPv4 they are forbidden.
|
||||||
|
#[rustfmt::skip]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! IPRE_BRACKET { () => (
|
||||||
|
concat!(r"(?:",
|
||||||
|
IPV4RE!(),
|
||||||
|
r"|\[(?:",
|
||||||
|
IPV6RE!(),
|
||||||
|
r")\]",
|
||||||
|
r")"))
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref IP_REGEX: Regex = Regex::new(concat!(r"^", IPRE!(), r"$")).unwrap();
|
||||||
|
pub static ref IP_BRACKET_REGEX: Regex =
|
||||||
|
Regex::new(concat!(r"^", IPRE_BRACKET!(), r"$")).unwrap();
|
||||||
|
pub static ref SHA256_HEX_REGEX: Regex = Regex::new(r"^[a-f0-9]{64}$").unwrap();
|
||||||
|
pub static ref SYSTEMD_DATETIME_REGEX: Regex =
|
||||||
|
Regex::new(r"^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}(:\d{2})?)?$").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_regexes() {
|
||||||
|
assert!(IP_REGEX.is_match("127.0.0.1"));
|
||||||
|
assert!(IP_REGEX.is_match("::1"));
|
||||||
|
assert!(IP_REGEX.is_match("2014:b3a::27"));
|
||||||
|
assert!(IP_REGEX.is_match("2014:b3a::192.168.0.1"));
|
||||||
|
assert!(IP_REGEX.is_match("2014:b3a:0102:adf1:1234:4321:4afA:BCDF"));
|
||||||
|
|
||||||
|
assert!(IP_BRACKET_REGEX.is_match("127.0.0.1"));
|
||||||
|
assert!(IP_BRACKET_REGEX.is_match("[::1]"));
|
||||||
|
assert!(IP_BRACKET_REGEX.is_match("[2014:b3a::27]"));
|
||||||
|
assert!(IP_BRACKET_REGEX.is_match("[2014:b3a::192.168.0.1]"));
|
||||||
|
assert!(IP_BRACKET_REGEX.is_match("[2014:b3a:0102:adf1:1234:4321:4afA:BCDF]"));
|
||||||
|
}
|
|
@ -51,7 +51,8 @@ impl std::str::FromStr for Fingerprint {
|
||||||
fn from_str(s: &str) -> Result<Self, Error> {
|
fn from_str(s: &str) -> Result<Self, Error> {
|
||||||
let mut tmp = s.to_string();
|
let mut tmp = s.to_string();
|
||||||
tmp.retain(|c| c != ':');
|
tmp.retain(|c| c != ':');
|
||||||
let bytes = proxmox::tools::hex_to_digest(&tmp)?;
|
let mut bytes = [0u8; 32];
|
||||||
|
hex::decode_to_slice(&tmp, &mut bytes)?;
|
||||||
Ok(Fingerprint::new(bytes))
|
Ok(Fingerprint::new(bytes))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,8 +216,8 @@ impl std::str::FromStr for HumanByte {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
proxmox::forward_deserialize_to_from_str!(HumanByte);
|
proxmox_serde::forward_deserialize_to_from_str!(HumanByte);
|
||||||
proxmox::forward_serialize_to_display!(HumanByte);
|
proxmox_serde::forward_serialize_to_display!(HumanByte);
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_human_byte_parser() -> Result<(), Error> {
|
fn test_human_byte_parser() -> Result<(), Error> {
|
||||||
|
|
|
@ -365,8 +365,8 @@ impl std::fmt::Display for GroupFilter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
proxmox::forward_deserialize_to_from_str!(GroupFilter);
|
proxmox_serde::forward_deserialize_to_from_str!(GroupFilter);
|
||||||
proxmox::forward_serialize_to_display!(GroupFilter);
|
proxmox_serde::forward_serialize_to_display!(GroupFilter);
|
||||||
|
|
||||||
fn verify_group_filter(input: &str) -> Result<(), anyhow::Error> {
|
fn verify_group_filter(input: &str) -> Result<(), anyhow::Error> {
|
||||||
GroupFilter::from_str(input).map(|_| ())
|
GroupFilter::from_str(input).map(|_| ())
|
||||||
|
|
|
@ -3,10 +3,11 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
|
|
||||||
|
pub mod common_regex;
|
||||||
|
|
||||||
use proxmox_schema::{
|
use proxmox_schema::{
|
||||||
api, const_regex, ApiStringFormat, ApiType, ArraySchema, Schema, StringSchema, ReturnType,
|
api, const_regex, ApiStringFormat, ApiType, ArraySchema, Schema, StringSchema, ReturnType,
|
||||||
};
|
};
|
||||||
use proxmox::{IPRE, IPRE_BRACKET, IPV4OCTET, IPV4RE, IPV6H16, IPV6LS32, IPV6RE};
|
|
||||||
use proxmox_time::parse_daily_duration;
|
use proxmox_time::parse_daily_duration;
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
|
@ -199,7 +200,7 @@ pub const DNS_NAME_OR_IP_SCHEMA: Schema = StringSchema::new("DNS name or IP addr
|
||||||
|
|
||||||
pub const NODE_SCHEMA: Schema = StringSchema::new("Node name (or 'localhost')")
|
pub const NODE_SCHEMA: Schema = StringSchema::new("Node name (or 'localhost')")
|
||||||
.format(&ApiStringFormat::VerifyFn(|node| {
|
.format(&ApiStringFormat::VerifyFn(|node| {
|
||||||
if node == "localhost" || node == proxmox::tools::nodename() {
|
if node == "localhost" || node == proxmox_sys::nodename() {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
bail!("no such node '{}'", node);
|
bail!("no such node '{}'", node);
|
||||||
|
|
|
@ -79,7 +79,7 @@ pub struct Remote {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
// Note: The stored password is base64 encoded
|
// Note: The stored password is base64 encoded
|
||||||
#[serde(skip_serializing_if="String::is_empty")]
|
#[serde(skip_serializing_if="String::is_empty")]
|
||||||
#[serde(with = "proxmox::tools::serde::string_as_base64")]
|
#[serde(with = "proxmox_serde::string_as_base64")]
|
||||||
pub password: String,
|
pub password: String,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub config: RemoteConfig,
|
pub config: RemoteConfig,
|
||||||
|
|
|
@ -22,8 +22,8 @@ pub enum MediaLocation {
|
||||||
Vault(String),
|
Vault(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
proxmox::forward_deserialize_to_from_str!(MediaLocation);
|
proxmox_serde::forward_deserialize_to_from_str!(MediaLocation);
|
||||||
proxmox::forward_serialize_to_display!(MediaLocation);
|
proxmox_serde::forward_serialize_to_display!(MediaLocation);
|
||||||
|
|
||||||
impl proxmox_schema::ApiType for MediaLocation {
|
impl proxmox_schema::ApiType for MediaLocation {
|
||||||
const API_SCHEMA: Schema = StringSchema::new(
|
const API_SCHEMA: Schema = StringSchema::new(
|
||||||
|
|
|
@ -685,8 +685,8 @@ fn test_token_id() {
|
||||||
assert_eq!(auth_id.to_string(), "test@pam!bar".to_string());
|
assert_eq!(auth_id.to_string(), "test@pam!bar".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
proxmox::forward_deserialize_to_from_str!(Userid);
|
proxmox_serde::forward_deserialize_to_from_str!(Userid);
|
||||||
proxmox::forward_serialize_to_display!(Userid);
|
proxmox_serde::forward_serialize_to_display!(Userid);
|
||||||
|
|
||||||
proxmox::forward_deserialize_to_from_str!(Authid);
|
proxmox_serde::forward_deserialize_to_from_str!(Authid);
|
||||||
proxmox::forward_serialize_to_display!(Authid);
|
proxmox_serde::forward_serialize_to_display!(Authid);
|
||||||
|
|
|
@ -10,6 +10,7 @@ anyhow = "1.0"
|
||||||
bitflags = "1.2.1"
|
bitflags = "1.2.1"
|
||||||
bytes = "1.0"
|
bytes = "1.0"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
|
hex = "0.4.3"
|
||||||
h2 = { version = "0.3", features = [ "stream" ] }
|
h2 = { version = "0.3", features = [ "stream" ] }
|
||||||
http = "0.2"
|
http = "0.2"
|
||||||
hyper = { version = "0.14", features = [ "full" ] }
|
hyper = { version = "0.14", features = [ "full" ] }
|
||||||
|
@ -28,15 +29,17 @@ tower-service = "0.3.0"
|
||||||
xdg = "2.2"
|
xdg = "2.2"
|
||||||
|
|
||||||
pathpatterns = "0.1.2"
|
pathpatterns = "0.1.2"
|
||||||
proxmox = "0.15.3"
|
|
||||||
proxmox-async = "0.2"
|
proxmox-async = "0.3"
|
||||||
proxmox-fuse = "0.1.1"
|
proxmox-fuse = "0.1.1"
|
||||||
proxmox-http = { version = "0.5.4", features = [ "client", "http-helpers", "websocket" ] }
|
proxmox-http = { version = "0.6", features = [ "client", "http-helpers", "websocket" ] }
|
||||||
proxmox-io = { version = "1", features = [ "tokio" ] }
|
proxmox-io = { version = "1", features = [ "tokio" ] }
|
||||||
proxmox-lang = "1"
|
proxmox-lang = "1"
|
||||||
proxmox-router = { version = "1.1", features = [ "cli" ] }
|
proxmox-router = { version = "1.1", features = [ "cli" ] }
|
||||||
proxmox-schema = "1"
|
proxmox-schema = "1"
|
||||||
proxmox-time = "1"
|
proxmox-time = "1"
|
||||||
|
proxmox-sys = "0.2"
|
||||||
|
|
||||||
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
|
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
|
||||||
|
|
||||||
pbs-api-types = { path = "../pbs-api-types" }
|
pbs-api-types = { path = "../pbs-api-types" }
|
||||||
|
|
|
@ -7,8 +7,6 @@ use std::os::unix::fs::OpenOptionsExt;
|
||||||
use futures::future::AbortHandle;
|
use futures::future::AbortHandle;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
use proxmox::tools::digest_to_hex;
|
|
||||||
|
|
||||||
use pbs_tools::crypt_config::CryptConfig;
|
use pbs_tools::crypt_config::CryptConfig;
|
||||||
use pbs_tools::sha::sha256;
|
use pbs_tools::sha::sha256;
|
||||||
use pbs_datastore::{PROXMOX_BACKUP_READER_PROTOCOL_ID_V1, BackupManifest};
|
use pbs_datastore::{PROXMOX_BACKUP_READER_PROTOCOL_ID_V1, BackupManifest};
|
||||||
|
@ -121,7 +119,7 @@ impl BackupReader {
|
||||||
output: W,
|
output: W,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let path = "chunk";
|
let path = "chunk";
|
||||||
let param = json!({ "digest": digest_to_hex(digest) });
|
let param = json!({ "digest": hex::encode(digest) });
|
||||||
self.h2.download(path, Some(param), output).await
|
self.h2.download(path, Some(param), output).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,6 @@ use tokio::io::AsyncReadExt;
|
||||||
use tokio::sync::{mpsc, oneshot};
|
use tokio::sync::{mpsc, oneshot};
|
||||||
use tokio_stream::wrappers::ReceiverStream;
|
use tokio_stream::wrappers::ReceiverStream;
|
||||||
|
|
||||||
use proxmox::tools::digest_to_hex;
|
|
||||||
|
|
||||||
use pbs_api_types::HumanByte;
|
use pbs_api_types::HumanByte;
|
||||||
use pbs_tools::crypt_config::CryptConfig;
|
use pbs_tools::crypt_config::CryptConfig;
|
||||||
use pbs_datastore::{CATALOG_NAME, PROXMOX_BACKUP_PROTOCOL_ID_V1};
|
use pbs_datastore::{CATALOG_NAME, PROXMOX_BACKUP_PROTOCOL_ID_V1};
|
||||||
|
@ -389,7 +387,7 @@ impl BackupWriter {
|
||||||
"wid": wid ,
|
"wid": wid ,
|
||||||
"chunk-count": upload_stats.chunk_count,
|
"chunk-count": upload_stats.chunk_count,
|
||||||
"size": upload_stats.size,
|
"size": upload_stats.size,
|
||||||
"csum": proxmox::tools::digest_to_hex(&upload_stats.csum),
|
"csum": hex::encode(&upload_stats.csum),
|
||||||
});
|
});
|
||||||
let _value = self.h2.post(&close_path, Some(param)).await?;
|
let _value = self.h2.post(&close_path, Some(param)).await?;
|
||||||
Ok(BackupStats {
|
Ok(BackupStats {
|
||||||
|
@ -481,7 +479,7 @@ impl BackupWriter {
|
||||||
let mut digest_list = vec![];
|
let mut digest_list = vec![];
|
||||||
let mut offset_list = vec![];
|
let mut offset_list = vec![];
|
||||||
for (offset, digest) in chunk_list {
|
for (offset, digest) in chunk_list {
|
||||||
digest_list.push(digest_to_hex(&digest));
|
digest_list.push(hex::encode(&digest));
|
||||||
offset_list.push(offset);
|
offset_list.push(offset);
|
||||||
}
|
}
|
||||||
if verbose { println!("append chunks list len ({})", digest_list.len()); }
|
if verbose { println!("append chunks list len ({})", digest_list.len()); }
|
||||||
|
@ -712,7 +710,7 @@ impl BackupWriter {
|
||||||
if let MergedChunkInfo::New(chunk_info) = merged_chunk_info {
|
if let MergedChunkInfo::New(chunk_info) = merged_chunk_info {
|
||||||
let offset = chunk_info.offset;
|
let offset = chunk_info.offset;
|
||||||
let digest = chunk_info.digest;
|
let digest = chunk_info.digest;
|
||||||
let digest_str = digest_to_hex(&digest);
|
let digest_str = hex::encode(&digest);
|
||||||
|
|
||||||
/* too verbose, needs finer verbosity setting granularity
|
/* too verbose, needs finer verbosity setting granularity
|
||||||
if verbose {
|
if verbose {
|
||||||
|
|
|
@ -14,7 +14,7 @@ use nix::fcntl::OFlag;
|
||||||
use nix::sys::stat::Mode;
|
use nix::sys::stat::Mode;
|
||||||
|
|
||||||
use pathpatterns::{MatchEntry, MatchList, MatchPattern, MatchType, PatternFlag};
|
use pathpatterns::{MatchEntry, MatchList, MatchPattern, MatchType, PatternFlag};
|
||||||
use proxmox::tools::fs::{create_path, CreateOptions};
|
use proxmox_sys::fs::{create_path, CreateOptions};
|
||||||
use proxmox_router::cli::{self, CliCommand, CliCommandMap, CliHelper, CommandLineInterface};
|
use proxmox_router::cli::{self, CliCommand, CliCommandMap, CliHelper, CommandLineInterface};
|
||||||
use proxmox_schema::api;
|
use proxmox_schema::api;
|
||||||
use pxar::{EntryKind, Metadata};
|
use pxar::{EntryKind, Metadata};
|
||||||
|
|
|
@ -14,10 +14,8 @@ use serde_json::{json, Value};
|
||||||
use percent_encoding::percent_encode;
|
use percent_encoding::percent_encode;
|
||||||
use xdg::BaseDirectories;
|
use xdg::BaseDirectories;
|
||||||
|
|
||||||
use proxmox::{
|
use proxmox_sys::linux::tty;
|
||||||
sys::linux::tty,
|
use proxmox_sys::fs::{file_get_json, replace_file, CreateOptions};
|
||||||
tools::fs::{file_get_json, replace_file, CreateOptions},
|
|
||||||
};
|
|
||||||
use proxmox_router::HttpError;
|
use proxmox_router::HttpError;
|
||||||
|
|
||||||
use proxmox_http::client::{HttpsConnector, RateLimiter};
|
use proxmox_http::client::{HttpsConnector, RateLimiter};
|
||||||
|
@ -521,7 +519,7 @@ impl HttpClient {
|
||||||
Ok(fp) => fp,
|
Ok(fp) => fp,
|
||||||
Err(err) => bail!("failed to calculate certificate FP - {}", err), // should not happen
|
Err(err) => bail!("failed to calculate certificate FP - {}", err), // should not happen
|
||||||
};
|
};
|
||||||
let fp_string = proxmox::tools::digest_to_hex(&fp);
|
let fp_string = hex::encode(&fp);
|
||||||
let fp_string = fp_string.as_bytes().chunks(2).map(|v| std::str::from_utf8(v).unwrap())
|
let fp_string = fp_string.as_bytes().chunks(2).map(|v| std::str::from_utf8(v).unwrap())
|
||||||
.collect::<Vec<&str>>().join(":");
|
.collect::<Vec<&str>>().join(":");
|
||||||
|
|
||||||
|
|
|
@ -19,14 +19,14 @@ use pathpatterns::{MatchEntry, MatchFlag, MatchList, MatchType, PatternFlag};
|
||||||
use pxar::Metadata;
|
use pxar::Metadata;
|
||||||
use pxar::encoder::{SeqWrite, LinkOffset};
|
use pxar::encoder::{SeqWrite, LinkOffset};
|
||||||
|
|
||||||
use proxmox::sys::error::SysError;
|
use proxmox_sys::error::SysError;
|
||||||
use proxmox::tools::fd::RawFdNum;
|
use proxmox_sys::fd::RawFdNum;
|
||||||
use proxmox::tools::fd::Fd;
|
use proxmox_sys::fd::Fd;
|
||||||
|
use proxmox_sys::fs::{self, acl, xattr};
|
||||||
use proxmox_io::vec;
|
use proxmox_io::vec;
|
||||||
use proxmox_lang::c_str;
|
use proxmox_lang::c_str;
|
||||||
|
|
||||||
use pbs_datastore::catalog::BackupCatalogWriter;
|
use pbs_datastore::catalog::BackupCatalogWriter;
|
||||||
use pbs_tools::{acl, fs, xattr};
|
|
||||||
use pbs_tools::str::strip_ascii_whitespace;
|
use pbs_tools::str::strip_ascii_whitespace;
|
||||||
|
|
||||||
use crate::pxar::metadata::errno_is_unsupported;
|
use crate::pxar::metadata::errno_is_unsupported;
|
||||||
|
@ -60,7 +60,7 @@ fn detect_fs_type(fd: RawFd) -> Result<i64, Error> {
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
pub fn is_virtual_file_system(magic: i64) -> bool {
|
pub fn is_virtual_file_system(magic: i64) -> bool {
|
||||||
use proxmox::sys::linux::magic::*;
|
use proxmox_sys::linux::magic::*;
|
||||||
|
|
||||||
matches!(magic, BINFMTFS_MAGIC |
|
matches!(magic, BINFMTFS_MAGIC |
|
||||||
CGROUP2_SUPER_MAGIC |
|
CGROUP2_SUPER_MAGIC |
|
||||||
|
@ -855,7 +855,7 @@ fn get_chattr(metadata: &mut Metadata, fd: RawFd) -> Result<(), Error> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_fat_attr(metadata: &mut Metadata, fd: RawFd, fs_magic: i64) -> Result<(), Error> {
|
fn get_fat_attr(metadata: &mut Metadata, fd: RawFd, fs_magic: i64) -> Result<(), Error> {
|
||||||
use proxmox::sys::linux::magic::*;
|
use proxmox_sys::linux::magic::*;
|
||||||
|
|
||||||
if fs_magic != MSDOS_SUPER_MAGIC && fs_magic != FUSE_SUPER_MAGIC {
|
if fs_magic != MSDOS_SUPER_MAGIC && fs_magic != FUSE_SUPER_MAGIC {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -891,7 +891,7 @@ fn get_quota_project_id(
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
use proxmox::sys::linux::magic::*;
|
use proxmox_sys::linux::magic::*;
|
||||||
|
|
||||||
match magic {
|
match magic {
|
||||||
EXT4_SUPER_MAGIC | XFS_SUPER_MAGIC | FUSE_SUPER_MAGIC | ZFS_SUPER_MAGIC => (),
|
EXT4_SUPER_MAGIC | XFS_SUPER_MAGIC | FUSE_SUPER_MAGIC | ZFS_SUPER_MAGIC => (),
|
||||||
|
|
|
@ -7,8 +7,8 @@ use nix::dir::Dir;
|
||||||
use nix::fcntl::OFlag;
|
use nix::fcntl::OFlag;
|
||||||
use nix::sys::stat::{mkdirat, Mode};
|
use nix::sys::stat::{mkdirat, Mode};
|
||||||
|
|
||||||
use proxmox::sys::error::SysError;
|
use proxmox_sys::error::SysError;
|
||||||
use proxmox::tools::fd::BorrowedFd;
|
use proxmox_sys::fd::BorrowedFd;
|
||||||
use pxar::Metadata;
|
use pxar::Metadata;
|
||||||
|
|
||||||
use crate::pxar::tools::{assert_single_path_component, perms_from_metadata};
|
use crate::pxar::tools::{assert_single_path_component, perms_from_metadata};
|
||||||
|
|
|
@ -21,8 +21,8 @@ use pxar::decoder::aio::Decoder;
|
||||||
use pxar::format::Device;
|
use pxar::format::Device;
|
||||||
use pxar::{Entry, EntryKind, Metadata};
|
use pxar::{Entry, EntryKind, Metadata};
|
||||||
|
|
||||||
use proxmox::c_result;
|
use proxmox_sys::c_result;
|
||||||
use proxmox::tools::fs::{create_path, CreateOptions};
|
use proxmox_sys::fs::{create_path, CreateOptions};
|
||||||
use proxmox_io::{sparse_copy, sparse_copy_async};
|
use proxmox_io::{sparse_copy, sparse_copy_async};
|
||||||
|
|
||||||
use proxmox_async::zip::{ZipEncoder, ZipEntry};
|
use proxmox_async::zip::{ZipEncoder, ZipEntry};
|
||||||
|
|
|
@ -255,7 +255,7 @@ impl Flags {
|
||||||
|
|
||||||
/// Return the supported *pxar* feature flags based on the magic number of the filesystem.
|
/// Return the supported *pxar* feature flags based on the magic number of the filesystem.
|
||||||
pub fn from_magic(magic: i64) -> Flags {
|
pub fn from_magic(magic: i64) -> Flags {
|
||||||
use proxmox::sys::linux::magic::*;
|
use proxmox_sys::linux::magic::*;
|
||||||
match magic {
|
match magic {
|
||||||
MSDOS_SUPER_MAGIC => {
|
MSDOS_SUPER_MAGIC => {
|
||||||
Flags::WITH_2SEC_TIME |
|
Flags::WITH_2SEC_TIME |
|
||||||
|
|
|
@ -25,8 +25,7 @@ use pxar::accessor::{self, EntryRangeInfo, ReadAt};
|
||||||
|
|
||||||
use proxmox_fuse::requests::{self, FuseRequest};
|
use proxmox_fuse::requests::{self, FuseRequest};
|
||||||
use proxmox_fuse::{EntryParam, Fuse, ReplyBufState, Request, ROOT_ID};
|
use proxmox_fuse::{EntryParam, Fuse, ReplyBufState, Request, ROOT_ID};
|
||||||
|
use proxmox_sys::fs::xattr;
|
||||||
use pbs_tools::xattr;
|
|
||||||
|
|
||||||
/// We mark inodes for regular files this way so we know how to access them.
|
/// We mark inodes for regular files this way so we know how to access them.
|
||||||
const NON_DIRECTORY_INODE: u64 = 1u64 << 63;
|
const NON_DIRECTORY_INODE: u64 = 1u64 << 63;
|
||||||
|
|
|
@ -9,11 +9,10 @@ use nix::sys::stat::Mode;
|
||||||
|
|
||||||
use pxar::Metadata;
|
use pxar::Metadata;
|
||||||
|
|
||||||
use proxmox::c_result;
|
use proxmox_sys::c_result;
|
||||||
use proxmox::sys::error::SysError;
|
use proxmox_sys::error::SysError;
|
||||||
use proxmox::tools::fd::RawFdNum;
|
use proxmox_sys::fd::RawFdNum;
|
||||||
|
use proxmox_sys::fs::{self, acl, xattr};
|
||||||
use pbs_tools::{acl, fs, xattr};
|
|
||||||
|
|
||||||
use crate::pxar::tools::perms_from_metadata;
|
use crate::pxar::tools::perms_from_metadata;
|
||||||
use crate::pxar::Flags;
|
use crate::pxar::Flags;
|
||||||
|
@ -67,7 +66,7 @@ pub fn apply_at(
|
||||||
path_info: &Path,
|
path_info: &Path,
|
||||||
on_error: &mut (dyn FnMut(Error) -> Result<(), Error> + Send),
|
on_error: &mut (dyn FnMut(Error) -> Result<(), Error> + Send),
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let fd = proxmox::tools::fd::Fd::openat(
|
let fd = proxmox_sys::fd::Fd::openat(
|
||||||
&unsafe { RawFdNum::from_raw_fd(parent) },
|
&unsafe { RawFdNum::from_raw_fd(parent) },
|
||||||
file_name,
|
file_name,
|
||||||
OFlag::O_PATH | OFlag::O_CLOEXEC | OFlag::O_NOFOLLOW,
|
OFlag::O_PATH | OFlag::O_CLOEXEC | OFlag::O_NOFOLLOW,
|
||||||
|
|
|
@ -6,8 +6,8 @@ use std::io::Read;
|
||||||
use anyhow::{bail, format_err, Error};
|
use anyhow::{bail, format_err, Error};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use proxmox::sys::linux::tty;
|
use proxmox_sys::linux::tty;
|
||||||
use proxmox::tools::fs::file_get_contents;
|
use proxmox_sys::fs::file_get_contents;
|
||||||
use proxmox_schema::*;
|
use proxmox_schema::*;
|
||||||
|
|
||||||
use pbs_api_types::CryptMode;
|
use pbs_api_types::CryptMode;
|
||||||
|
@ -374,7 +374,7 @@ fn create_testdir(name: &str) -> Result<String, Error> {
|
||||||
// safe w.r.t. concurrency
|
// safe w.r.t. concurrency
|
||||||
fn test_crypto_parameters_handling() -> Result<(), Error> {
|
fn test_crypto_parameters_handling() -> Result<(), Error> {
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use proxmox::tools::fs::{replace_file, CreateOptions};
|
use proxmox_sys::fs::{replace_file, CreateOptions};
|
||||||
|
|
||||||
let some_key = vec![1;1];
|
let some_key = vec![1;1];
|
||||||
let default_key = vec![2;1];
|
let default_key = vec![2;1];
|
||||||
|
|
|
@ -12,7 +12,7 @@ use xdg::BaseDirectories;
|
||||||
|
|
||||||
use proxmox_schema::*;
|
use proxmox_schema::*;
|
||||||
use proxmox_router::cli::{complete_file_name, shellword_split};
|
use proxmox_router::cli::{complete_file_name, shellword_split};
|
||||||
use proxmox::tools::fs::file_get_json;
|
use proxmox_sys::fs::file_get_json;
|
||||||
|
|
||||||
use pbs_api_types::{BACKUP_REPO_URL, Authid, RateLimitConfig, UserWithTokens};
|
use pbs_api_types::{BACKUP_REPO_URL, Authid, RateLimitConfig, UserWithTokens};
|
||||||
use pbs_datastore::BackupDir;
|
use pbs_datastore::BackupDir;
|
||||||
|
@ -100,7 +100,7 @@ pub fn get_secret_from_env(base_name: &str) -> Result<Option<String>, Error> {
|
||||||
let args = shellword_split(command)?;
|
let args = shellword_split(command)?;
|
||||||
let mut command = Command::new(&args[0]);
|
let mut command = Command::new(&args[0]);
|
||||||
command.args(&args[1..]);
|
command.args(&args[1..]);
|
||||||
let output = pbs_tools::run_command(command, None)?;
|
let output = proxmox_sys::command::run_command(command, None)?;
|
||||||
return Ok(Some(firstline(output)));
|
return Ok(Some(firstline(output)));
|
||||||
}
|
}
|
||||||
Err(NotUnicode(_)) => bail!(format!("{} contains bad characters", env_name)),
|
Err(NotUnicode(_)) => bail!(format!("{} contains bad characters", env_name)),
|
||||||
|
|
|
@ -17,14 +17,14 @@ regex = "1.2"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|
||||||
proxmox = "0.15.3"
|
|
||||||
proxmox-lang = "1"
|
proxmox-lang = "1"
|
||||||
proxmox-router = { version = "1.1", default-features = false }
|
proxmox-router = { version = "1.1", default-features = false }
|
||||||
proxmox-schema = "1"
|
proxmox-schema = "1"
|
||||||
proxmox-section-config = "1"
|
proxmox-section-config = "1"
|
||||||
proxmox-time = "1"
|
proxmox-time = "1"
|
||||||
proxmox-shared-memory = "0.1.1"
|
proxmox-serde = "0.1"
|
||||||
proxmox-sys = "0.1.2"
|
proxmox-shared-memory = "0.2"
|
||||||
|
proxmox-sys = "0.2"
|
||||||
|
|
||||||
pbs-api-types = { path = "../pbs-api-types" }
|
pbs-api-types = { path = "../pbs-api-types" }
|
||||||
pbs-buildcfg = { path = "../pbs-buildcfg" }
|
pbs-buildcfg = { path = "../pbs-buildcfg" }
|
||||||
|
|
|
@ -7,7 +7,7 @@ use anyhow::{bail, Error};
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use nix::sys::stat::Mode;
|
use nix::sys::stat::Mode;
|
||||||
|
|
||||||
use proxmox::tools::fs::{create_path, CreateOptions};
|
use proxmox_sys::fs::{create_path, CreateOptions};
|
||||||
|
|
||||||
// openssl::sha::sha256(b"Proxmox Backup ConfigVersionCache v1.0")[0..8];
|
// openssl::sha::sha256(b"Proxmox Backup ConfigVersionCache v1.0")[0..8];
|
||||||
pub const PROXMOX_BACKUP_CONFIG_VERSION_CACHE_MAGIC_1_0: [u8; 8] = [25, 198, 168, 230, 154, 132, 143, 131];
|
pub const PROXMOX_BACKUP_CONFIG_VERSION_CACHE_MAGIC_1_0: [u8; 8] = [25, 198, 168, 230, 154, 132, 143, 131];
|
||||||
|
|
|
@ -36,7 +36,7 @@ pub fn lock_config() -> Result<BackupLockGuard, Error> {
|
||||||
|
|
||||||
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
|
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
|
||||||
|
|
||||||
let content = proxmox::tools::fs::file_read_optional_string(DATASTORE_CFG_FILENAME)?
|
let content = proxmox_sys::fs::file_read_optional_string(DATASTORE_CFG_FILENAME)?
|
||||||
.unwrap_or_else(|| "".to_string());
|
.unwrap_or_else(|| "".to_string());
|
||||||
|
|
||||||
let digest = openssl::sha::sha256(content.as_bytes());
|
let digest = openssl::sha::sha256(content.as_bytes());
|
||||||
|
|
|
@ -37,7 +37,7 @@ pub fn lock_config() -> Result<BackupLockGuard, Error> {
|
||||||
|
|
||||||
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
|
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
|
||||||
|
|
||||||
let content = proxmox::tools::fs::file_read_optional_string(DOMAINS_CFG_FILENAME)?
|
let content = proxmox_sys::fs::file_read_optional_string(DOMAINS_CFG_FILENAME)?
|
||||||
.unwrap_or_else(|| "".to_string());
|
.unwrap_or_else(|| "".to_string());
|
||||||
|
|
||||||
let digest = openssl::sha::sha256(content.as_bytes());
|
let digest = openssl::sha::sha256(content.as_bytes());
|
||||||
|
|
|
@ -71,7 +71,7 @@ pub fn lock() -> Result<BackupLockGuard, Error> {
|
||||||
/// Read and parse the configuration file
|
/// Read and parse the configuration file
|
||||||
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
|
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
|
||||||
|
|
||||||
let content = proxmox::tools::fs::file_read_optional_string(DRIVE_CFG_FILENAME)?
|
let content = proxmox_sys::fs::file_read_optional_string(DRIVE_CFG_FILENAME)?
|
||||||
.unwrap_or_else(|| "".to_string());
|
.unwrap_or_else(|| "".to_string());
|
||||||
|
|
||||||
let digest = openssl::sha::sha256(content.as_bytes());
|
let digest = openssl::sha::sha256(content.as_bytes());
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::path::Path;
|
||||||
use anyhow::{bail, format_err, Context, Error};
|
use anyhow::{bail, format_err, Context, Error};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use proxmox::tools::fs::{file_get_contents, replace_file, CreateOptions};
|
use proxmox_sys::fs::{file_get_contents, replace_file, CreateOptions};
|
||||||
use proxmox_lang::try_block;
|
use proxmox_lang::try_block;
|
||||||
|
|
||||||
use pbs_api_types::{Kdf, KeyInfo, Fingerprint};
|
use pbs_api_types::{Kdf, KeyInfo, Fingerprint};
|
||||||
|
@ -18,12 +18,12 @@ pub enum KeyDerivationConfig {
|
||||||
n: u64,
|
n: u64,
|
||||||
r: u64,
|
r: u64,
|
||||||
p: u64,
|
p: u64,
|
||||||
#[serde(with = "proxmox::tools::serde::bytes_as_base64")]
|
#[serde(with = "proxmox_serde::bytes_as_base64")]
|
||||||
salt: Vec<u8>,
|
salt: Vec<u8>,
|
||||||
},
|
},
|
||||||
PBKDF2 {
|
PBKDF2 {
|
||||||
iter: usize,
|
iter: usize,
|
||||||
#[serde(with = "proxmox::tools::serde::bytes_as_base64")]
|
#[serde(with = "proxmox_serde::bytes_as_base64")]
|
||||||
salt: Vec<u8>,
|
salt: Vec<u8>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -72,11 +72,11 @@ impl KeyDerivationConfig {
|
||||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||||
pub struct KeyConfig {
|
pub struct KeyConfig {
|
||||||
pub kdf: Option<KeyDerivationConfig>,
|
pub kdf: Option<KeyDerivationConfig>,
|
||||||
#[serde(with = "proxmox::tools::serde::epoch_as_rfc3339")]
|
#[serde(with = "proxmox_serde::epoch_as_rfc3339")]
|
||||||
pub created: i64,
|
pub created: i64,
|
||||||
#[serde(with = "proxmox::tools::serde::epoch_as_rfc3339")]
|
#[serde(with = "proxmox_serde::epoch_as_rfc3339")]
|
||||||
pub modified: i64,
|
pub modified: i64,
|
||||||
#[serde(with = "proxmox::tools::serde::bytes_as_base64")]
|
#[serde(with = "proxmox_serde::bytes_as_base64")]
|
||||||
pub data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
@ -111,7 +111,7 @@ impl KeyConfig {
|
||||||
/// Creates a new key using random data, protected by passphrase.
|
/// Creates a new key using random data, protected by passphrase.
|
||||||
pub fn new(passphrase: &[u8], kdf: Kdf) -> Result<([u8;32], Self), Error> {
|
pub fn new(passphrase: &[u8], kdf: Kdf) -> Result<([u8;32], Self), Error> {
|
||||||
let mut key = [0u8; 32];
|
let mut key = [0u8; 32];
|
||||||
proxmox::sys::linux::fill_with_random_data(&mut key)?;
|
proxmox_sys::linux::fill_with_random_data(&mut key)?;
|
||||||
let key_config = Self::with_key(&key, passphrase, kdf)?;
|
let key_config = Self::with_key(&key, passphrase, kdf)?;
|
||||||
Ok((key, key_config))
|
Ok((key, key_config))
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ impl KeyConfig {
|
||||||
bail!("got strange key length ({} != 32)", raw_key.len())
|
bail!("got strange key length ({} != 32)", raw_key.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
let salt = proxmox::sys::linux::random_data(32)?;
|
let salt = proxmox_sys::linux::random_data(32)?;
|
||||||
|
|
||||||
let kdf = match kdf {
|
let kdf = match kdf {
|
||||||
Kdf::Scrypt => KeyDerivationConfig::Scrypt {
|
Kdf::Scrypt => KeyDerivationConfig::Scrypt {
|
||||||
|
@ -166,7 +166,7 @@ impl KeyConfig {
|
||||||
|
|
||||||
let cipher = openssl::symm::Cipher::aes_256_gcm();
|
let cipher = openssl::symm::Cipher::aes_256_gcm();
|
||||||
|
|
||||||
let iv = proxmox::sys::linux::random_data(16)?;
|
let iv = proxmox_sys::linux::random_data(16)?;
|
||||||
let mut tag = [0u8; 16];
|
let mut tag = [0u8; 16];
|
||||||
|
|
||||||
let encrypted_key = openssl::symm::encrypt_aead(
|
let encrypted_key = openssl::symm::encrypt_aead(
|
||||||
|
|
|
@ -55,14 +55,14 @@ pub fn open_backup_lockfile<P: AsRef<std::path::Path>>(
|
||||||
exclusive: bool,
|
exclusive: bool,
|
||||||
) -> Result<BackupLockGuard, Error> {
|
) -> Result<BackupLockGuard, Error> {
|
||||||
let user = backup_user()?;
|
let user = backup_user()?;
|
||||||
let options = proxmox::tools::fs::CreateOptions::new()
|
let options = proxmox_sys::fs::CreateOptions::new()
|
||||||
.perm(nix::sys::stat::Mode::from_bits_truncate(0o660))
|
.perm(nix::sys::stat::Mode::from_bits_truncate(0o660))
|
||||||
.owner(user.uid)
|
.owner(user.uid)
|
||||||
.group(user.gid);
|
.group(user.gid);
|
||||||
|
|
||||||
let timeout = timeout.unwrap_or(std::time::Duration::new(10, 0));
|
let timeout = timeout.unwrap_or(std::time::Duration::new(10, 0));
|
||||||
|
|
||||||
let file = proxmox::tools::fs::open_file_locked(&path, timeout, exclusive, options)?;
|
let file = proxmox_sys::fs::open_file_locked(&path, timeout, exclusive, options)?;
|
||||||
Ok(BackupLockGuard(Some(file)))
|
Ok(BackupLockGuard(Some(file)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,12 +77,12 @@ pub fn replace_backup_config<P: AsRef<std::path::Path>>(
|
||||||
let mode = nix::sys::stat::Mode::from_bits_truncate(0o0640);
|
let mode = nix::sys::stat::Mode::from_bits_truncate(0o0640);
|
||||||
// set the correct owner/group/permissions while saving file
|
// set the correct owner/group/permissions while saving file
|
||||||
// owner(rw) = root, group(r)= backup
|
// owner(rw) = root, group(r)= backup
|
||||||
let options = proxmox::tools::fs::CreateOptions::new()
|
let options = proxmox_sys::fs::CreateOptions::new()
|
||||||
.perm(mode)
|
.perm(mode)
|
||||||
.owner(nix::unistd::ROOT)
|
.owner(nix::unistd::ROOT)
|
||||||
.group(backup_user.gid);
|
.group(backup_user.gid);
|
||||||
|
|
||||||
proxmox::tools::fs::replace_file(path, data, options, true)?;
|
proxmox_sys::fs::replace_file(path, data, options, true)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -97,12 +97,12 @@ pub fn replace_secret_config<P: AsRef<std::path::Path>>(
|
||||||
let mode = nix::sys::stat::Mode::from_bits_truncate(0o0600);
|
let mode = nix::sys::stat::Mode::from_bits_truncate(0o0600);
|
||||||
// set the correct owner/group/permissions while saving file
|
// set the correct owner/group/permissions while saving file
|
||||||
// owner(rw) = root, group(r)= root
|
// owner(rw) = root, group(r)= root
|
||||||
let options = proxmox::tools::fs::CreateOptions::new()
|
let options = proxmox_sys::fs::CreateOptions::new()
|
||||||
.perm(mode)
|
.perm(mode)
|
||||||
.owner(nix::unistd::ROOT)
|
.owner(nix::unistd::ROOT)
|
||||||
.group(nix::unistd::Gid::from_raw(0));
|
.group(nix::unistd::Gid::from_raw(0));
|
||||||
|
|
||||||
proxmox::tools::fs::replace_file(path, data, options, true)?;
|
proxmox_sys::fs::replace_file(path, data, options, true)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ pub fn lock() -> Result<BackupLockGuard, Error> {
|
||||||
/// Read and parse the configuration file
|
/// Read and parse the configuration file
|
||||||
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
|
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
|
||||||
|
|
||||||
let content = proxmox::tools::fs::file_read_optional_string(MEDIA_POOL_CFG_FILENAME)?
|
let content = proxmox_sys::fs::file_read_optional_string(MEDIA_POOL_CFG_FILENAME)?
|
||||||
.unwrap_or_else(|| "".to_string());
|
.unwrap_or_else(|| "".to_string());
|
||||||
|
|
||||||
let digest = openssl::sha::sha256(content.as_bytes());
|
let digest = openssl::sha::sha256(content.as_bytes());
|
||||||
|
|
|
@ -9,8 +9,9 @@ use nix::ioctl_read_bad;
|
||||||
use nix::sys::socket::{socket, AddressFamily, SockType, SockFlag};
|
use nix::sys::socket::{socket, AddressFamily, SockType, SockFlag};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
use proxmox::*; // for IP macros
|
use pbs_api_types::*; // for IP macros
|
||||||
use proxmox::tools::fd::Fd;
|
|
||||||
|
use proxmox_sys::fd::Fd;
|
||||||
|
|
||||||
pub static IPV4_REVERSE_MASK: &[&str] = &[
|
pub static IPV4_REVERSE_MASK: &[&str] = &[
|
||||||
"0.0.0.0",
|
"0.0.0.0",
|
||||||
|
@ -188,7 +189,7 @@ pub fn compute_file_diff(filename: &str, shadow: &str) -> Result<String, Error>
|
||||||
.output()
|
.output()
|
||||||
.map_err(|err| format_err!("failed to execute diff - {}", err))?;
|
.map_err(|err| format_err!("failed to execute diff - {}", err))?;
|
||||||
|
|
||||||
let diff = pbs_tools::command_output_as_string(output, Some(|c| c == 0 || c == 1))
|
let diff = proxmox_sys::command::command_output_as_string(output, Some(|c| c == 0 || c == 1))
|
||||||
.map_err(|err| format_err!("diff failed: {}", err))?;
|
.map_err(|err| format_err!("diff failed: {}", err))?;
|
||||||
|
|
||||||
Ok(diff)
|
Ok(diff)
|
||||||
|
@ -209,7 +210,7 @@ pub fn network_reload() -> Result<(), Error> {
|
||||||
.output()
|
.output()
|
||||||
.map_err(|err| format_err!("failed to execute 'ifreload' - {}", err))?;
|
.map_err(|err| format_err!("failed to execute 'ifreload' - {}", err))?;
|
||||||
|
|
||||||
pbs_tools::command_output(output, None)
|
proxmox_sys::command::command_output(output, None)
|
||||||
.map_err(|err| format_err!("ifreload failed: {}", err))?;
|
.map_err(|err| format_err!("ifreload failed: {}", err))?;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ use serde::de::{value, IntoDeserializer, Deserialize};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
use proxmox::tools::{fs::replace_file, fs::CreateOptions};
|
use proxmox_sys::{fs::replace_file, fs::CreateOptions};
|
||||||
|
|
||||||
mod helper;
|
mod helper;
|
||||||
pub use helper::*;
|
pub use helper::*;
|
||||||
|
@ -409,10 +409,10 @@ pub fn lock_config() -> Result<BackupLockGuard, Error> {
|
||||||
|
|
||||||
pub fn config() -> Result<(NetworkConfig, [u8;32]), Error> {
|
pub fn config() -> Result<(NetworkConfig, [u8;32]), Error> {
|
||||||
|
|
||||||
let content = match proxmox::tools::fs::file_get_optional_contents(NETWORK_INTERFACES_NEW_FILENAME)? {
|
let content = match proxmox_sys::fs::file_get_optional_contents(NETWORK_INTERFACES_NEW_FILENAME)? {
|
||||||
Some(content) => content,
|
Some(content) => content,
|
||||||
None => {
|
None => {
|
||||||
let content = proxmox::tools::fs::file_get_optional_contents(NETWORK_INTERFACES_FILENAME)?;
|
let content = proxmox_sys::fs::file_get_optional_contents(NETWORK_INTERFACES_FILENAME)?;
|
||||||
content.unwrap_or_default()
|
content.unwrap_or_default()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -184,7 +184,7 @@ impl <R: BufRead> NetworkParser<R> {
|
||||||
self.eat(Token::Gateway)?;
|
self.eat(Token::Gateway)?;
|
||||||
let gateway = self.next_text()?;
|
let gateway = self.next_text()?;
|
||||||
|
|
||||||
if proxmox::tools::common_regex::IP_REGEX.is_match(&gateway) {
|
if pbs_api_types::common_regex::IP_REGEX.is_match(&gateway) {
|
||||||
if gateway.contains(':') {
|
if gateway.contains(':') {
|
||||||
set_gateway_v6(interface, gateway)?;
|
set_gateway_v6(interface, gateway)?;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -37,7 +37,7 @@ pub fn lock_config() -> Result<BackupLockGuard, Error> {
|
||||||
|
|
||||||
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
|
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
|
||||||
|
|
||||||
let content = proxmox::tools::fs::file_read_optional_string(REMOTE_CFG_FILENAME)?
|
let content = proxmox_sys::fs::file_read_optional_string(REMOTE_CFG_FILENAME)?
|
||||||
.unwrap_or_else(|| "".to_string());
|
.unwrap_or_else(|| "".to_string());
|
||||||
|
|
||||||
let digest = openssl::sha::sha256(content.as_bytes());
|
let digest = openssl::sha::sha256(content.as_bytes());
|
||||||
|
|
|
@ -38,7 +38,7 @@ pub fn lock_config() -> Result<BackupLockGuard, Error> {
|
||||||
|
|
||||||
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
|
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
|
||||||
|
|
||||||
let content = proxmox::tools::fs::file_read_optional_string(SYNC_CFG_FILENAME)?
|
let content = proxmox_sys::fs::file_read_optional_string(SYNC_CFG_FILENAME)?
|
||||||
.unwrap_or_else(|| "".to_string());
|
.unwrap_or_else(|| "".to_string());
|
||||||
|
|
||||||
let digest = openssl::sha::sha256(content.as_bytes());
|
let digest = openssl::sha::sha256(content.as_bytes());
|
||||||
|
|
|
@ -15,7 +15,7 @@ use std::collections::HashMap;
|
||||||
use anyhow::{bail, Error};
|
use anyhow::{bail, Error};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use proxmox::tools::fs::file_read_optional_string;
|
use proxmox_sys::fs::file_read_optional_string;
|
||||||
use pbs_api_types::Fingerprint;
|
use pbs_api_types::Fingerprint;
|
||||||
|
|
||||||
use crate::key_config::KeyConfig;
|
use crate::key_config::KeyConfig;
|
||||||
|
@ -23,7 +23,8 @@ use crate::{open_backup_lockfile, replace_secret_config, replace_backup_config};
|
||||||
|
|
||||||
mod hex_key {
|
mod hex_key {
|
||||||
use serde::{self, Deserialize, Serializer, Deserializer};
|
use serde::{self, Deserialize, Serializer, Deserializer};
|
||||||
|
use hex::FromHex;
|
||||||
|
|
||||||
pub fn serialize<S>(
|
pub fn serialize<S>(
|
||||||
csum: &[u8; 32],
|
csum: &[u8; 32],
|
||||||
serializer: S,
|
serializer: S,
|
||||||
|
@ -31,7 +32,7 @@ mod hex_key {
|
||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
let s = proxmox::tools::digest_to_hex(csum);
|
let s = hex::encode(csum);
|
||||||
serializer.serialize_str(&s)
|
serializer.serialize_str(&s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +43,7 @@ mod hex_key {
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
let s = String::deserialize(deserializer)?;
|
let s = String::deserialize(deserializer)?;
|
||||||
proxmox::tools::hex_to_digest(&s).map_err(serde::de::Error::custom)
|
<[u8; 32]>::from_hex(&s).map_err(serde::de::Error::custom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ pub fn lock() -> Result<BackupLockGuard, Error> {
|
||||||
|
|
||||||
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
|
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
|
||||||
|
|
||||||
let content = proxmox::tools::fs::file_read_optional_string(TAPE_JOB_CFG_FILENAME)?
|
let content = proxmox_sys::fs::file_read_optional_string(TAPE_JOB_CFG_FILENAME)?
|
||||||
.unwrap_or_else(|| "".to_string());
|
.unwrap_or_else(|| "".to_string());
|
||||||
|
|
||||||
let digest = openssl::sha::sha256(content.as_bytes());
|
let digest = openssl::sha::sha256(content.as_bytes());
|
||||||
|
|
|
@ -4,7 +4,7 @@ use anyhow::{bail, format_err, Error};
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use serde_json::{from_value, Value};
|
use serde_json::{from_value, Value};
|
||||||
|
|
||||||
use proxmox::tools::fs::CreateOptions;
|
use proxmox_sys::fs::CreateOptions;
|
||||||
|
|
||||||
use pbs_api_types::Authid;
|
use pbs_api_types::Authid;
|
||||||
//use crate::auth;
|
//use crate::auth;
|
||||||
|
@ -27,7 +27,7 @@ fn lock_config() -> Result<BackupLockGuard, Error> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_file() -> Result<HashMap<Authid, String>, Error> {
|
fn read_file() -> Result<HashMap<Authid, String>, Error> {
|
||||||
let json = proxmox::tools::fs::file_get_json(CONF_FILE, Some(Value::Null))?;
|
let json = proxmox_sys::fs::file_get_json(CONF_FILE, Some(Value::Null))?;
|
||||||
|
|
||||||
if json == Value::Null {
|
if json == Value::Null {
|
||||||
Ok(HashMap::new())
|
Ok(HashMap::new())
|
||||||
|
@ -45,7 +45,7 @@ fn write_file(data: HashMap<Authid, String>) -> Result<(), Error> {
|
||||||
.group(backup_user.gid);
|
.group(backup_user.gid);
|
||||||
|
|
||||||
let json = serde_json::to_vec(&data)?;
|
let json = serde_json::to_vec(&data)?;
|
||||||
proxmox::tools::fs::replace_file(CONF_FILE, &json, options, true)
|
proxmox_sys::fs::replace_file(CONF_FILE, &json, options, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ pub fn lock_config() -> Result<BackupLockGuard, Error> {
|
||||||
/// Read and parse the configuration file
|
/// Read and parse the configuration file
|
||||||
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
|
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
|
||||||
|
|
||||||
let content = proxmox::tools::fs::file_read_optional_string(TRAFFIC_CONTROL_CFG_FILENAME)?
|
let content = proxmox_sys::fs::file_read_optional_string(TRAFFIC_CONTROL_CFG_FILENAME)?
|
||||||
.unwrap_or_else(|| "".to_string());
|
.unwrap_or_else(|| "".to_string());
|
||||||
|
|
||||||
let digest = openssl::sha::sha256(content.as_bytes());
|
let digest = openssl::sha::sha256(content.as_bytes());
|
||||||
|
|
|
@ -49,7 +49,7 @@ pub fn lock_config() -> Result<BackupLockGuard, Error> {
|
||||||
|
|
||||||
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
|
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
|
||||||
|
|
||||||
let content = proxmox::tools::fs::file_read_optional_string(USER_CFG_FILENAME)?
|
let content = proxmox_sys::fs::file_read_optional_string(USER_CFG_FILENAME)?
|
||||||
.unwrap_or_else(|| "".to_string());
|
.unwrap_or_else(|| "".to_string());
|
||||||
|
|
||||||
let digest = openssl::sha::sha256(content.as_bytes());
|
let digest = openssl::sha::sha256(content.as_bytes());
|
||||||
|
|
|
@ -37,7 +37,7 @@ pub fn lock_config() -> Result<BackupLockGuard, Error> {
|
||||||
|
|
||||||
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
|
pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> {
|
||||||
|
|
||||||
let content = proxmox::tools::fs::file_read_optional_string(VERIFICATION_CFG_FILENAME)?;
|
let content = proxmox_sys::fs::file_read_optional_string(VERIFICATION_CFG_FILENAME)?;
|
||||||
let content = content.unwrap_or_else(String::new);
|
let content = content.unwrap_or_else(String::new);
|
||||||
|
|
||||||
let digest = openssl::sha::sha256(content.as_bytes());
|
let digest = openssl::sha::sha256(content.as_bytes());
|
||||||
|
|
|
@ -11,6 +11,7 @@ base64 = "0.13"
|
||||||
crc32fast = "1"
|
crc32fast = "1"
|
||||||
endian_trait = { version = "0.6", features = [ "arrays" ] }
|
endian_trait = { version = "0.6", features = [ "arrays" ] }
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
|
hex = "0.4.3"
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
@ -25,14 +26,13 @@ zstd = { version = "0.6", features = [ "bindgen" ] }
|
||||||
pathpatterns = "0.1.2"
|
pathpatterns = "0.1.2"
|
||||||
pxar = "0.10.1"
|
pxar = "0.10.1"
|
||||||
|
|
||||||
proxmox = "0.15.3"
|
|
||||||
proxmox-borrow = "1"
|
proxmox-borrow = "1"
|
||||||
proxmox-io = "1"
|
proxmox-io = "1"
|
||||||
proxmox-lang = "1"
|
proxmox-lang = "1"
|
||||||
proxmox-schema = { version = "1", features = [ "api-macro" ] }
|
proxmox-schema = { version = "1", features = [ "api-macro" ] }
|
||||||
proxmox-time = "1"
|
proxmox-time = "1"
|
||||||
proxmox-uuid = "1"
|
proxmox-uuid = "1"
|
||||||
proxmox-sys = "0.1.2"
|
proxmox-sys = "0.2"
|
||||||
|
|
||||||
pbs-api-types = { path = "../pbs-api-types" }
|
pbs-api-types = { path = "../pbs-api-types" }
|
||||||
pbs-tools = { path = "../pbs-tools" }
|
pbs-tools = { path = "../pbs-tools" }
|
||||||
|
|
|
@ -81,7 +81,7 @@ impl BackupGroup {
|
||||||
let mut path = base_path.to_owned();
|
let mut path = base_path.to_owned();
|
||||||
path.push(self.group_path());
|
path.push(self.group_path());
|
||||||
|
|
||||||
pbs_tools::fs::scandir(
|
proxmox_sys::fs::scandir(
|
||||||
libc::AT_FDCWD,
|
libc::AT_FDCWD,
|
||||||
&path,
|
&path,
|
||||||
&BACKUP_DATE_REGEX,
|
&BACKUP_DATE_REGEX,
|
||||||
|
@ -110,7 +110,7 @@ impl BackupGroup {
|
||||||
let mut path = base_path.to_owned();
|
let mut path = base_path.to_owned();
|
||||||
path.push(self.group_path());
|
path.push(self.group_path());
|
||||||
|
|
||||||
pbs_tools::fs::scandir(
|
proxmox_sys::fs::scandir(
|
||||||
libc::AT_FDCWD,
|
libc::AT_FDCWD,
|
||||||
&path,
|
&path,
|
||||||
&BACKUP_DATE_REGEX,
|
&BACKUP_DATE_REGEX,
|
||||||
|
@ -369,7 +369,7 @@ impl BackupInfo {
|
||||||
pub fn list_backup_groups(base_path: &Path) -> Result<Vec<BackupGroup>, Error> {
|
pub fn list_backup_groups(base_path: &Path) -> Result<Vec<BackupGroup>, Error> {
|
||||||
let mut list = Vec::new();
|
let mut list = Vec::new();
|
||||||
|
|
||||||
pbs_tools::fs::scandir(
|
proxmox_sys::fs::scandir(
|
||||||
libc::AT_FDCWD,
|
libc::AT_FDCWD,
|
||||||
base_path,
|
base_path,
|
||||||
&BACKUP_TYPE_REGEX,
|
&BACKUP_TYPE_REGEX,
|
||||||
|
@ -377,7 +377,7 @@ impl BackupInfo {
|
||||||
if file_type != nix::dir::Type::Directory {
|
if file_type != nix::dir::Type::Directory {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
pbs_tools::fs::scandir(
|
proxmox_sys::fs::scandir(
|
||||||
l0_fd,
|
l0_fd,
|
||||||
backup_type,
|
backup_type,
|
||||||
&BACKUP_ID_REGEX,
|
&BACKUP_ID_REGEX,
|
||||||
|
@ -411,7 +411,7 @@ fn list_backup_files<P: ?Sized + nix::NixPath>(
|
||||||
) -> Result<Vec<String>, Error> {
|
) -> Result<Vec<String>, Error> {
|
||||||
let mut files = vec![];
|
let mut files = vec![];
|
||||||
|
|
||||||
pbs_tools::fs::scandir(dirfd, path, &BACKUP_FILE_REGEX, |_, filename, file_type| {
|
proxmox_sys::fs::scandir(dirfd, path, &BACKUP_FILE_REGEX, |_, filename, file_type| {
|
||||||
if file_type != nix::dir::Type::File {
|
if file_type != nix::dir::Type::File {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,8 @@ use anyhow::Error;
|
||||||
use futures::ready;
|
use futures::ready;
|
||||||
use tokio::io::{AsyncRead, AsyncSeek, ReadBuf};
|
use tokio::io::{AsyncRead, AsyncSeek, ReadBuf};
|
||||||
|
|
||||||
use proxmox::io_format_err;
|
use proxmox_sys::io_format_err;
|
||||||
use proxmox::sys::error::io_err_other;
|
use proxmox_sys::error::io_err_other;
|
||||||
|
|
||||||
use pbs_tools::async_lru_cache::{AsyncCacher, AsyncLruCache};
|
use pbs_tools::async_lru_cache::{AsyncCacher, AsyncLruCache};
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,9 @@ use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use anyhow::{bail, format_err, Error};
|
use anyhow::{bail, format_err, Error};
|
||||||
|
|
||||||
use proxmox::tools::fs::{CreateOptions, create_path, create_dir};
|
use proxmox_sys::fs::{CreateOptions, create_path, create_dir};
|
||||||
use proxmox_sys::process_locker::{ProcessLocker, ProcessLockSharedGuard, ProcessLockExclusiveGuard};
|
use proxmox_sys::process_locker::{ProcessLocker, ProcessLockSharedGuard, ProcessLockExclusiveGuard};
|
||||||
use proxmox_sys::worker_task_context::WorkerTaskContext;
|
use proxmox_sys::WorkerTaskContext;
|
||||||
use proxmox_sys::task_log;
|
use proxmox_sys::task_log;
|
||||||
use pbs_api_types::GarbageCollectionStatus;
|
use pbs_api_types::GarbageCollectionStatus;
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ impl ChunkStore {
|
||||||
|
|
||||||
// create lock file with correct owner/group
|
// create lock file with correct owner/group
|
||||||
let lockfile_path = Self::lockfile_path(&base);
|
let lockfile_path = Self::lockfile_path(&base);
|
||||||
proxmox::tools::fs::replace_file(lockfile_path, b"", options.clone(), false)?;
|
proxmox_sys::fs::replace_file(lockfile_path, b"", options.clone(), false)?;
|
||||||
|
|
||||||
// create 64*1024 subdirs
|
// create 64*1024 subdirs
|
||||||
let mut last_percentage = 0;
|
let mut last_percentage = 0;
|
||||||
|
@ -194,7 +194,7 @@ impl ChunkStore {
|
||||||
pub fn get_chunk_iterator(
|
pub fn get_chunk_iterator(
|
||||||
&self,
|
&self,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
impl Iterator<Item = (Result<pbs_tools::fs::ReadDirEntry, Error>, usize, bool)> + std::iter::FusedIterator,
|
impl Iterator<Item = (Result<proxmox_sys::fs::ReadDirEntry, Error>, usize, bool)> + std::iter::FusedIterator,
|
||||||
Error
|
Error
|
||||||
> {
|
> {
|
||||||
use nix::dir::Dir;
|
use nix::dir::Dir;
|
||||||
|
@ -212,7 +212,7 @@ impl ChunkStore {
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let mut done = false;
|
let mut done = false;
|
||||||
let mut inner: Option<pbs_tools::fs::ReadDir> = None;
|
let mut inner: Option<proxmox_sys::fs::ReadDir> = None;
|
||||||
let mut at = 0;
|
let mut at = 0;
|
||||||
let mut percentage = 0;
|
let mut percentage = 0;
|
||||||
Ok(std::iter::from_fn(move || {
|
Ok(std::iter::from_fn(move || {
|
||||||
|
@ -256,7 +256,7 @@ impl ChunkStore {
|
||||||
let subdir: &str = &format!("{:04x}", at);
|
let subdir: &str = &format!("{:04x}", at);
|
||||||
percentage = (at * 100) / 0x10000;
|
percentage = (at * 100) / 0x10000;
|
||||||
at += 1;
|
at += 1;
|
||||||
match pbs_tools::fs::read_subdir(base_handle.as_raw_fd(), subdir) {
|
match proxmox_sys::fs::read_subdir(base_handle.as_raw_fd(), subdir) {
|
||||||
Ok(dir) => {
|
Ok(dir) => {
|
||||||
inner = Some(dir);
|
inner = Some(dir);
|
||||||
// start reading:
|
// start reading:
|
||||||
|
@ -382,7 +382,7 @@ impl ChunkStore {
|
||||||
digest: &[u8; 32],
|
digest: &[u8; 32],
|
||||||
) -> Result<(bool, u64), Error> {
|
) -> Result<(bool, u64), Error> {
|
||||||
|
|
||||||
//println!("DIGEST {}", proxmox::tools::digest_to_hex(digest));
|
//println!("DIGEST {}", hex::encode(digest));
|
||||||
|
|
||||||
let (chunk_path, digest_str) = self.chunk_path(digest);
|
let (chunk_path, digest_str) = self.chunk_path(digest);
|
||||||
|
|
||||||
|
@ -440,7 +440,7 @@ impl ChunkStore {
|
||||||
let mut chunk_path = self.chunk_dir.clone();
|
let mut chunk_path = self.chunk_dir.clone();
|
||||||
let prefix = digest_to_prefix(digest);
|
let prefix = digest_to_prefix(digest);
|
||||||
chunk_path.push(&prefix);
|
chunk_path.push(&prefix);
|
||||||
let digest_str = proxmox::tools::digest_to_hex(digest);
|
let digest_str = hex::encode(digest);
|
||||||
chunk_path.push(&digest_str);
|
chunk_path.push(&digest_str);
|
||||||
(chunk_path, digest_str)
|
(chunk_path, digest_str)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ impl <W: Write> CryptWriter<W> {
|
||||||
|
|
||||||
pub fn new(writer: W, config: Arc<CryptConfig>) -> Result<Self, Error> {
|
pub fn new(writer: W, config: Arc<CryptConfig>) -> Result<Self, Error> {
|
||||||
let mut iv = [0u8; 16];
|
let mut iv = [0u8; 16];
|
||||||
proxmox::sys::linux::fill_with_random_data(&mut iv)?;
|
proxmox_sys::linux::fill_with_random_data(&mut iv)?;
|
||||||
let block_size = config.cipher().block_size();
|
let block_size = config.cipher().block_size();
|
||||||
|
|
||||||
let crypter = config.data_crypter(&iv, openssl::symm::Mode::Encrypt)?;
|
let crypter = config.data_crypter(&iv, openssl::symm::Mode::Encrypt)?;
|
||||||
|
|
|
@ -347,7 +347,7 @@ impl DataBlob {
|
||||||
) -> Result<([u8;16], [u8;16]), Error> {
|
) -> Result<([u8;16], [u8;16]), Error> {
|
||||||
|
|
||||||
let mut iv = [0u8; 16];
|
let mut iv = [0u8; 16];
|
||||||
proxmox::sys::linux::fill_with_random_data(&mut iv)?;
|
proxmox_sys::linux::fill_with_random_data(&mut iv)?;
|
||||||
|
|
||||||
let mut tag = [0u8; 16];
|
let mut tag = [0u8; 16];
|
||||||
|
|
||||||
|
|
|
@ -9,13 +9,13 @@ use std::time::Duration;
|
||||||
use anyhow::{bail, format_err, Error};
|
use anyhow::{bail, format_err, Error};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
use proxmox::tools::fs::{replace_file, file_read_optional_string, CreateOptions};
|
use proxmox_sys::fs::{replace_file, file_read_optional_string, CreateOptions};
|
||||||
use proxmox_sys::process_locker::ProcessLockSharedGuard;
|
use proxmox_sys::process_locker::ProcessLockSharedGuard;
|
||||||
use proxmox_sys::worker_task_context::WorkerTaskContext;
|
use proxmox_sys::WorkerTaskContext;
|
||||||
use proxmox_sys::{task_log, task_warn};
|
use proxmox_sys::{task_log, task_warn};
|
||||||
|
use proxmox_sys::fs::{lock_dir_noblock, DirLockGuard};
|
||||||
|
|
||||||
use pbs_api_types::{UPID, DataStoreConfig, Authid, GarbageCollectionStatus, HumanByte};
|
use pbs_api_types::{UPID, DataStoreConfig, Authid, GarbageCollectionStatus, HumanByte};
|
||||||
use pbs_tools::fs::{lock_dir_noblock, DirLockGuard};
|
|
||||||
use pbs_config::{open_backup_lockfile, BackupLockGuard};
|
use pbs_config::{open_backup_lockfile, BackupLockGuard};
|
||||||
|
|
||||||
use crate::DataBlob;
|
use crate::DataBlob;
|
||||||
|
@ -127,7 +127,7 @@ impl DataStore {
|
||||||
pub fn get_chunk_iterator(
|
pub fn get_chunk_iterator(
|
||||||
&self,
|
&self,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
impl Iterator<Item = (Result<pbs_tools::fs::ReadDirEntry, Error>, usize, bool)>,
|
impl Iterator<Item = (Result<proxmox_sys::fs::ReadDirEntry, Error>, usize, bool)>,
|
||||||
Error
|
Error
|
||||||
> {
|
> {
|
||||||
self.chunk_store.get_chunk_iterator()
|
self.chunk_store.get_chunk_iterator()
|
||||||
|
@ -199,7 +199,7 @@ impl DataStore {
|
||||||
map_err(|err| {
|
map_err(|err| {
|
||||||
format_err!(
|
format_err!(
|
||||||
"fast_index_verification error, stat_chunk {} failed - {}",
|
"fast_index_verification error, stat_chunk {} failed - {}",
|
||||||
proxmox::tools::digest_to_hex(&info.digest),
|
hex::encode(&info.digest),
|
||||||
err,
|
err,
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
@ -232,7 +232,7 @@ impl DataStore {
|
||||||
wanted_files.insert(CLIENT_LOG_BLOB_NAME.to_string());
|
wanted_files.insert(CLIENT_LOG_BLOB_NAME.to_string());
|
||||||
manifest.files().iter().for_each(|item| { wanted_files.insert(item.filename.clone()); });
|
manifest.files().iter().for_each(|item| { wanted_files.insert(item.filename.clone()); });
|
||||||
|
|
||||||
for item in pbs_tools::fs::read_subdir(libc::AT_FDCWD, &full_path)? {
|
for item in proxmox_sys::fs::read_subdir(libc::AT_FDCWD, &full_path)? {
|
||||||
if let Ok(item) = item {
|
if let Ok(item) = item {
|
||||||
if let Some(file_type) = item.file_type() {
|
if let Some(file_type) = item.file_type() {
|
||||||
if file_type != nix::dir::Type::File { continue; }
|
if file_type != nix::dir::Type::File { continue; }
|
||||||
|
@ -272,7 +272,7 @@ impl DataStore {
|
||||||
|
|
||||||
let full_path = self.group_path(backup_group);
|
let full_path = self.group_path(backup_group);
|
||||||
|
|
||||||
let _guard = pbs_tools::fs::lock_dir_noblock(&full_path, "backup group", "possible running backup")?;
|
let _guard = proxmox_sys::fs::lock_dir_noblock(&full_path, "backup group", "possible running backup")?;
|
||||||
|
|
||||||
log::info!("removing backup group {:?}", full_path);
|
log::info!("removing backup group {:?}", full_path);
|
||||||
|
|
||||||
|
@ -358,7 +358,7 @@ impl DataStore {
|
||||||
let mut full_path = self.base_path();
|
let mut full_path = self.base_path();
|
||||||
full_path.push(backup_group.group_path());
|
full_path.push(backup_group.group_path());
|
||||||
full_path.push("owner");
|
full_path.push("owner");
|
||||||
let owner = proxmox::tools::fs::file_read_firstline(full_path)?;
|
let owner = proxmox_sys::fs::file_read_firstline(full_path)?;
|
||||||
Ok(owner.trim_end().parse()?) // remove trailing newline
|
Ok(owner.trim_end().parse()?) // remove trailing newline
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,7 +525,7 @@ impl DataStore {
|
||||||
task_warn!(
|
task_warn!(
|
||||||
worker,
|
worker,
|
||||||
"warning: unable to access non-existent chunk {}, required by {:?}",
|
"warning: unable to access non-existent chunk {}, required by {:?}",
|
||||||
proxmox::tools::digest_to_hex(digest),
|
hex::encode(digest),
|
||||||
file_name,
|
file_name,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ use std::task::Context;
|
||||||
|
|
||||||
use anyhow::{bail, format_err, Error};
|
use anyhow::{bail, format_err, Error};
|
||||||
|
|
||||||
use proxmox::tools::mmap::Mmap;
|
use proxmox_sys::mmap::Mmap;
|
||||||
use proxmox_io::ReadExt;
|
use proxmox_io::ReadExt;
|
||||||
use proxmox_uuid::Uuid;
|
use proxmox_uuid::Uuid;
|
||||||
use proxmox_sys::process_locker::ProcessLockSharedGuard;
|
use proxmox_sys::process_locker::ProcessLockSharedGuard;
|
||||||
|
@ -467,7 +467,7 @@ impl DynamicChunkWriter {
|
||||||
chunk_size,
|
chunk_size,
|
||||||
(compressed_size * 100) / (chunk_size as u64),
|
(compressed_size * 100) / (chunk_size as u64),
|
||||||
is_duplicate,
|
is_duplicate,
|
||||||
proxmox::tools::digest_to_hex(&digest)
|
hex::encode(&digest)
|
||||||
);
|
);
|
||||||
self.index.add_chunk(self.chunk_offset as u64, &digest)?;
|
self.index.add_chunk(self.chunk_offset as u64, &digest)?;
|
||||||
self.chunk_buffer.truncate(0);
|
self.chunk_buffer.truncate(0);
|
||||||
|
|
|
@ -424,7 +424,7 @@ impl FixedIndexWriter {
|
||||||
chunk_len,
|
chunk_len,
|
||||||
(compressed_size * 100) / (chunk_len as u64),
|
(compressed_size * 100) / (chunk_len as u64),
|
||||||
is_duplicate,
|
is_duplicate,
|
||||||
proxmox::tools::digest_to_hex(digest)
|
hex::encode(digest)
|
||||||
);
|
);
|
||||||
|
|
||||||
if is_duplicate {
|
if is_duplicate {
|
||||||
|
|
|
@ -18,6 +18,7 @@ pub const ENCRYPTED_KEY_BLOB_NAME: &str = "rsa-encrypted.key.blob";
|
||||||
|
|
||||||
mod hex_csum {
|
mod hex_csum {
|
||||||
use serde::{self, Deserialize, Serializer, Deserializer};
|
use serde::{self, Deserialize, Serializer, Deserializer};
|
||||||
|
use hex::FromHex;
|
||||||
|
|
||||||
pub fn serialize<S>(
|
pub fn serialize<S>(
|
||||||
csum: &[u8; 32],
|
csum: &[u8; 32],
|
||||||
|
@ -26,7 +27,7 @@ mod hex_csum {
|
||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
let s = proxmox::tools::digest_to_hex(csum);
|
let s = hex::encode(csum);
|
||||||
serializer.serialize_str(&s)
|
serializer.serialize_str(&s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +38,7 @@ mod hex_csum {
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
let s = String::deserialize(deserializer)?;
|
let s = String::deserialize(deserializer)?;
|
||||||
proxmox::tools::hex_to_digest(&s).map_err(serde::de::Error::custom)
|
<[u8; 32]>::from_hex(&s).map_err(serde::de::Error::custom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +191,7 @@ impl BackupManifest {
|
||||||
|
|
||||||
if let Some(crypt_config) = crypt_config {
|
if let Some(crypt_config) = crypt_config {
|
||||||
let sig = self.signature(crypt_config)?;
|
let sig = self.signature(crypt_config)?;
|
||||||
manifest["signature"] = proxmox::tools::digest_to_hex(&sig).into();
|
manifest["signature"] = hex::encode(&sig).into();
|
||||||
let fingerprint = &Fingerprint::new(crypt_config.fingerprint());
|
let fingerprint = &Fingerprint::new(crypt_config.fingerprint());
|
||||||
manifest["unprotected"]["key-fingerprint"] = serde_json::to_value(fingerprint)?;
|
manifest["unprotected"]["key-fingerprint"] = serde_json::to_value(fingerprint)?;
|
||||||
}
|
}
|
||||||
|
@ -240,7 +241,7 @@ impl BackupManifest {
|
||||||
|
|
||||||
if let Some(ref crypt_config) = crypt_config {
|
if let Some(ref crypt_config) = crypt_config {
|
||||||
if let Some(signature) = signature {
|
if let Some(signature) = signature {
|
||||||
let expected_signature = proxmox::tools::digest_to_hex(&Self::json_signature(&json, crypt_config)?);
|
let expected_signature = hex::encode(&Self::json_signature(&json, crypt_config)?);
|
||||||
|
|
||||||
let fingerprint = &json["unprotected"]["key-fingerprint"];
|
let fingerprint = &json["unprotected"]["key-fingerprint"];
|
||||||
if fingerprint != &Value::Null {
|
if fingerprint != &Value::Null {
|
||||||
|
@ -318,7 +319,7 @@ fn test_manifest_signature() -> Result<(), Error> {
|
||||||
assert_eq!(signature, "d7b446fb7db081662081d4b40fedd858a1d6307a5aff4ecff7d5bf4fd35679e9");
|
assert_eq!(signature, "d7b446fb7db081662081d4b40fedd858a1d6307a5aff4ecff7d5bf4fd35679e9");
|
||||||
|
|
||||||
let manifest: BackupManifest = serde_json::from_value(manifest)?;
|
let manifest: BackupManifest = serde_json::from_value(manifest)?;
|
||||||
let expected_signature = proxmox::tools::digest_to_hex(&manifest.signature(&crypt_config)?);
|
let expected_signature = hex::encode(&manifest.signature(&crypt_config)?);
|
||||||
|
|
||||||
assert_eq!(signature, expected_signature);
|
assert_eq!(signature, expected_signature);
|
||||||
|
|
||||||
|
|
|
@ -247,7 +247,7 @@ fn generate_qr_code(output_type: &str, lines: &[String]) -> Result<Vec<u8>, Erro
|
||||||
.wait_with_output()
|
.wait_with_output()
|
||||||
.map_err(|_| format_err!("Failed to read stdout"))?;
|
.map_err(|_| format_err!("Failed to read stdout"))?;
|
||||||
|
|
||||||
let output = pbs_tools::command_output(output, None)?;
|
let output = proxmox_sys::command::command_output(output, None)?;
|
||||||
|
|
||||||
Ok(output)
|
Ok(output)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,13 +6,14 @@ use std::fs::File;
|
||||||
use anyhow::{bail, Error};
|
use anyhow::{bail, Error};
|
||||||
use nix::dir::Dir;
|
use nix::dir::Dir;
|
||||||
|
|
||||||
|
use proxmox_sys::fs::lock_dir_noblock_shared;
|
||||||
|
|
||||||
use crate::backup_info::BackupDir;
|
use crate::backup_info::BackupDir;
|
||||||
use crate::index::IndexFile;
|
use crate::index::IndexFile;
|
||||||
use crate::fixed_index::FixedIndexReader;
|
use crate::fixed_index::FixedIndexReader;
|
||||||
use crate::dynamic_index::DynamicIndexReader;
|
use crate::dynamic_index::DynamicIndexReader;
|
||||||
use crate::manifest::{archive_type, ArchiveType, CLIENT_LOG_BLOB_NAME, MANIFEST_BLOB_NAME};
|
use crate::manifest::{archive_type, ArchiveType, CLIENT_LOG_BLOB_NAME, MANIFEST_BLOB_NAME};
|
||||||
use crate::DataStore;
|
use crate::DataStore;
|
||||||
use pbs_tools::fs::lock_dir_noblock_shared;
|
|
||||||
|
|
||||||
/// Helper to access the contents of a datastore backup snapshot
|
/// Helper to access the contents of a datastore backup snapshot
|
||||||
///
|
///
|
||||||
|
|
|
@ -16,5 +16,4 @@ tokio = { version = "1.6", features = [] }
|
||||||
|
|
||||||
proxmox-time = "1"
|
proxmox-time = "1"
|
||||||
proxmox-fuse = "0.1.1"
|
proxmox-fuse = "0.1.1"
|
||||||
|
proxmox-sys = "0.2"
|
||||||
pbs-tools = { path = "../pbs-tools" }
|
|
|
@ -304,7 +304,7 @@ fn emerg_cleanup(loopdev: Option<&str>, mut backing_file: PathBuf) {
|
||||||
let mut command = std::process::Command::new("fusermount");
|
let mut command = std::process::Command::new("fusermount");
|
||||||
command.arg("-u");
|
command.arg("-u");
|
||||||
command.arg(&backing_file);
|
command.arg(&backing_file);
|
||||||
let _ = pbs_tools::run_command(command, None);
|
let _ = proxmox_sys::command::run_command(command, None);
|
||||||
|
|
||||||
let _ = remove_file(&backing_file);
|
let _ = remove_file(&backing_file);
|
||||||
backing_file.set_extension("pid");
|
backing_file.set_extension("pid");
|
||||||
|
@ -365,7 +365,7 @@ fn unmap_from_backing(backing_file: &Path, loopdev: Option<&str>) -> Result<(),
|
||||||
pub fn find_all_mappings() -> Result<impl Iterator<Item = (String, Option<String>)>, Error> {
|
pub fn find_all_mappings() -> Result<impl Iterator<Item = (String, Option<String>)>, Error> {
|
||||||
// get map of all /dev/loop mappings belonging to us
|
// get map of all /dev/loop mappings belonging to us
|
||||||
let mut loopmap = HashMap::new();
|
let mut loopmap = HashMap::new();
|
||||||
for ent in pbs_tools::fs::scan_subdir(libc::AT_FDCWD, Path::new("/dev/"), &LOOPDEV_REGEX)? {
|
for ent in proxmox_sys::fs::scan_subdir(libc::AT_FDCWD, Path::new("/dev/"), &LOOPDEV_REGEX)? {
|
||||||
if let Ok(ent) = ent {
|
if let Ok(ent) = ent {
|
||||||
let loopdev = format!("/dev/{}", ent.file_name().to_string_lossy());
|
let loopdev = format!("/dev/{}", ent.file_name().to_string_lossy());
|
||||||
if let Ok(file) = get_backing_file(&loopdev) {
|
if let Ok(file) = get_backing_file(&loopdev) {
|
||||||
|
@ -376,7 +376,7 @@ pub fn find_all_mappings() -> Result<impl Iterator<Item = (String, Option<String
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(
|
Ok(
|
||||||
pbs_tools::fs::read_subdir(libc::AT_FDCWD, Path::new(RUN_DIR))?.filter_map(move |ent| {
|
proxmox_sys::fs::read_subdir(libc::AT_FDCWD, Path::new(RUN_DIR))?.filter_map(move |ent| {
|
||||||
match ent {
|
match ent {
|
||||||
Ok(ent) => {
|
Ok(ent) => {
|
||||||
let file = ent.file_name().to_string_lossy();
|
let file = ent.file_name().to_string_lossy();
|
||||||
|
|
|
@ -11,6 +11,7 @@ libc = "0.2"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
endian_trait = { version = "0.6", features = ["arrays"] }
|
endian_trait = { version = "0.6", features = ["arrays"] }
|
||||||
|
hex = "0.4.3"
|
||||||
nix = "0.19.1"
|
nix = "0.19.1"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
@ -18,7 +19,6 @@ bitflags = "1.2.1"
|
||||||
regex = "1.2"
|
regex = "1.2"
|
||||||
udev = "0.4"
|
udev = "0.4"
|
||||||
|
|
||||||
proxmox = "0.15.3"
|
|
||||||
proxmox-io = "1"
|
proxmox-io = "1"
|
||||||
proxmox-lang = "1"
|
proxmox-lang = "1"
|
||||||
# api-macro is only used by the binaries, so maybe we should split them out
|
# api-macro is only used by the binaries, so maybe we should split them out
|
||||||
|
@ -28,6 +28,7 @@ proxmox-uuid = "1"
|
||||||
|
|
||||||
# router::cli is only used by binaries, so maybe we should split them out
|
# router::cli is only used by binaries, so maybe we should split them out
|
||||||
proxmox-router = "1.1"
|
proxmox-router = "1.1"
|
||||||
|
proxmox-sys = "0.2"
|
||||||
|
|
||||||
pbs-api-types = { path = "../pbs-api-types" }
|
pbs-api-types = { path = "../pbs-api-types" }
|
||||||
pbs-tools = { path = "../pbs-tools" }
|
pbs-tools = { path = "../pbs-tools" }
|
||||||
|
|
|
@ -69,11 +69,11 @@ impl <R: BlockRead> BlockedReader<R> {
|
||||||
fn check_buffer(buffer: &BlockHeader, seq_nr: u32) -> Result<(usize, bool), std::io::Error> {
|
fn check_buffer(buffer: &BlockHeader, seq_nr: u32) -> Result<(usize, bool), std::io::Error> {
|
||||||
|
|
||||||
if buffer.magic != PROXMOX_TAPE_BLOCK_HEADER_MAGIC_1_0 {
|
if buffer.magic != PROXMOX_TAPE_BLOCK_HEADER_MAGIC_1_0 {
|
||||||
proxmox::io_bail!("detected tape block with wrong magic number - not written by proxmox tape");
|
proxmox_sys::io_bail!("detected tape block with wrong magic number - not written by proxmox tape");
|
||||||
}
|
}
|
||||||
|
|
||||||
if seq_nr != buffer.seq_nr() {
|
if seq_nr != buffer.seq_nr() {
|
||||||
proxmox::io_bail!(
|
proxmox_sys::io_bail!(
|
||||||
"detected tape block with wrong sequence number ({} != {})",
|
"detected tape block with wrong sequence number ({} != {})",
|
||||||
seq_nr, buffer.seq_nr())
|
seq_nr, buffer.seq_nr())
|
||||||
}
|
}
|
||||||
|
@ -82,9 +82,9 @@ impl <R: BlockRead> BlockedReader<R> {
|
||||||
let found_end_marker = buffer.flags.contains(BlockHeaderFlags::END_OF_STREAM);
|
let found_end_marker = buffer.flags.contains(BlockHeaderFlags::END_OF_STREAM);
|
||||||
|
|
||||||
if size > buffer.payload.len() {
|
if size > buffer.payload.len() {
|
||||||
proxmox::io_bail!("detected tape block with wrong payload size ({} > {}", size, buffer.payload.len());
|
proxmox_sys::io_bail!("detected tape block with wrong payload size ({} > {}", size, buffer.payload.len());
|
||||||
} else if size == 0 && !found_end_marker {
|
} else if size == 0 && !found_end_marker {
|
||||||
proxmox::io_bail!("detected tape block with zero payload size");
|
proxmox_sys::io_bail!("detected tape block with zero payload size");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ impl <R: BlockRead> BlockedReader<R> {
|
||||||
let bytes = reader.read_block(data)?;
|
let bytes = reader.read_block(data)?;
|
||||||
|
|
||||||
if bytes != BlockHeader::SIZE {
|
if bytes != BlockHeader::SIZE {
|
||||||
return Err(proxmox::io_format_err!("got wrong block size").into());
|
return Err(proxmox_sys::io_format_err!("got wrong block size").into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -113,13 +113,13 @@ impl <R: BlockRead> BlockedReader<R> {
|
||||||
let mut tmp_buf = [0u8; 512]; // use a small buffer for testing EOF
|
let mut tmp_buf = [0u8; 512]; // use a small buffer for testing EOF
|
||||||
match reader.read_block(&mut tmp_buf) {
|
match reader.read_block(&mut tmp_buf) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
proxmox::io_bail!("detected tape block after block-stream end marker");
|
proxmox_sys::io_bail!("detected tape block after block-stream end marker");
|
||||||
}
|
}
|
||||||
Err(BlockReadError::EndOfFile) => {
|
Err(BlockReadError::EndOfFile) => {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
Err(BlockReadError::EndOfStream) => {
|
Err(BlockReadError::EndOfStream) => {
|
||||||
proxmox::io_bail!("got unexpected end of tape");
|
proxmox_sys::io_bail!("got unexpected end of tape");
|
||||||
}
|
}
|
||||||
Err(BlockReadError::Error(err)) => {
|
Err(BlockReadError::Error(err)) => {
|
||||||
return Err(err);
|
return Err(err);
|
||||||
|
@ -135,12 +135,12 @@ impl <R: BlockRead> BlockedReader<R> {
|
||||||
self.got_eod = true;
|
self.got_eod = true;
|
||||||
self.read_pos = self.buffer.payload.len();
|
self.read_pos = self.buffer.payload.len();
|
||||||
if !self.found_end_marker && check_end_marker {
|
if !self.found_end_marker && check_end_marker {
|
||||||
proxmox::io_bail!("detected tape stream without end marker");
|
proxmox_sys::io_bail!("detected tape stream without end marker");
|
||||||
}
|
}
|
||||||
return Ok(0); // EOD
|
return Ok(0); // EOD
|
||||||
}
|
}
|
||||||
Err(BlockReadError::EndOfStream) => {
|
Err(BlockReadError::EndOfStream) => {
|
||||||
proxmox::io_bail!("got unexpected end of tape");
|
proxmox_sys::io_bail!("got unexpected end of tape");
|
||||||
}
|
}
|
||||||
Err(BlockReadError::Error(err)) => {
|
Err(BlockReadError::Error(err)) => {
|
||||||
return Err(err);
|
return Err(err);
|
||||||
|
@ -167,10 +167,10 @@ impl <R: BlockRead> TapeRead for BlockedReader<R> {
|
||||||
|
|
||||||
fn is_incomplete(&self) -> Result<bool, std::io::Error> {
|
fn is_incomplete(&self) -> Result<bool, std::io::Error> {
|
||||||
if !self.got_eod {
|
if !self.got_eod {
|
||||||
proxmox::io_bail!("is_incomplete failed: EOD not reached");
|
proxmox_sys::io_bail!("is_incomplete failed: EOD not reached");
|
||||||
}
|
}
|
||||||
if !self.found_end_marker {
|
if !self.found_end_marker {
|
||||||
proxmox::io_bail!("is_incomplete failed: no end marker found");
|
proxmox_sys::io_bail!("is_incomplete failed: no end marker found");
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(self.incomplete)
|
Ok(self.incomplete)
|
||||||
|
@ -178,7 +178,7 @@ impl <R: BlockRead> TapeRead for BlockedReader<R> {
|
||||||
|
|
||||||
fn has_end_marker(&self) -> Result<bool, std::io::Error> {
|
fn has_end_marker(&self) -> Result<bool, std::io::Error> {
|
||||||
if !self.got_eod {
|
if !self.got_eod {
|
||||||
proxmox::io_bail!("has_end_marker failed: EOD not reached");
|
proxmox_sys::io_bail!("has_end_marker failed: EOD not reached");
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(self.found_end_marker)
|
Ok(self.found_end_marker)
|
||||||
|
@ -207,7 +207,7 @@ impl <R: BlockRead> Read for BlockedReader<R> {
|
||||||
fn read(&mut self, buffer: &mut [u8]) -> Result<usize, std::io::Error> {
|
fn read(&mut self, buffer: &mut [u8]) -> Result<usize, std::io::Error> {
|
||||||
|
|
||||||
if self.read_error {
|
if self.read_error {
|
||||||
proxmox::io_bail!("detected read after error - internal error");
|
proxmox_sys::io_bail!("detected read after error - internal error");
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut buffer_size = self.buffer.size();
|
let mut buffer_size = self.buffer.size();
|
||||||
|
@ -299,7 +299,7 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn large_data() -> Result<(), Error> {
|
fn large_data() -> Result<(), Error> {
|
||||||
let data = proxmox::sys::linux::random_data(1024*1024*5)?;
|
let data = proxmox_sys::linux::random_data(1024*1024*5)?;
|
||||||
write_and_verify(&data)
|
write_and_verify(&data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,7 +323,7 @@ mod test {
|
||||||
let writer = EmulateTapeWriter::new(&mut tape_data, 1024*1024);
|
let writer = EmulateTapeWriter::new(&mut tape_data, 1024*1024);
|
||||||
let mut writer = BlockedWriter::new(writer);
|
let mut writer = BlockedWriter::new(writer);
|
||||||
// write at least one block
|
// write at least one block
|
||||||
let data = proxmox::sys::linux::random_data(PROXMOX_TAPE_BLOCK_SIZE)?;
|
let data = proxmox_sys::linux::random_data(PROXMOX_TAPE_BLOCK_SIZE)?;
|
||||||
writer.write_all(&data)?;
|
writer.write_all(&data)?;
|
||||||
// but do not call finish here
|
// but do not call finish here
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ impl <W: BlockWrite> BlockedWriter<W> {
|
||||||
|
|
||||||
fn write_eof(&mut self) -> Result<(), std::io::Error> {
|
fn write_eof(&mut self) -> Result<(), std::io::Error> {
|
||||||
if self.wrote_eof {
|
if self.wrote_eof {
|
||||||
proxmox::io_bail!("BlockedWriter: detected multiple EOF writes");
|
proxmox_sys::io_bail!("BlockedWriter: detected multiple EOF writes");
|
||||||
}
|
}
|
||||||
self.wrote_eof = true;
|
self.wrote_eof = true;
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ impl <R: Read> EmulateTapeReader<R> {
|
||||||
impl <R: Read> BlockRead for EmulateTapeReader<R> {
|
impl <R: Read> BlockRead for EmulateTapeReader<R> {
|
||||||
fn read_block(&mut self, buffer: &mut [u8]) -> Result<usize, BlockReadError> {
|
fn read_block(&mut self, buffer: &mut [u8]) -> Result<usize, BlockReadError> {
|
||||||
if self.got_eof {
|
if self.got_eof {
|
||||||
return Err(BlockReadError::Error(proxmox::io_format_err!("detected read after EOF!")));
|
return Err(BlockReadError::Error(proxmox_sys::io_format_err!("detected read after EOF!")));
|
||||||
}
|
}
|
||||||
match self.reader.read_exact_or_eof(buffer)? {
|
match self.reader.read_exact_or_eof(buffer)? {
|
||||||
false => {
|
false => {
|
||||||
|
@ -33,7 +33,7 @@ impl <R: Read> BlockRead for EmulateTapeReader<R> {
|
||||||
// test buffer len after EOF test (to allow EOF test with small buffers in BufferedReader)
|
// test buffer len after EOF test (to allow EOF test with small buffers in BufferedReader)
|
||||||
if buffer.len() != PROXMOX_TAPE_BLOCK_SIZE {
|
if buffer.len() != PROXMOX_TAPE_BLOCK_SIZE {
|
||||||
return Err(BlockReadError::Error(
|
return Err(BlockReadError::Error(
|
||||||
proxmox::io_format_err!(
|
proxmox_sys::io_format_err!(
|
||||||
"EmulateTapeReader: read_block with wrong block size ({} != {})",
|
"EmulateTapeReader: read_block with wrong block size ({} != {})",
|
||||||
buffer.len(),
|
buffer.len(),
|
||||||
PROXMOX_TAPE_BLOCK_SIZE,
|
PROXMOX_TAPE_BLOCK_SIZE,
|
||||||
|
|
|
@ -39,7 +39,7 @@ impl <W: Write> BlockWrite for EmulateTapeWriter<W> {
|
||||||
fn write_block(&mut self, buffer: &[u8]) -> Result<bool, io::Error> {
|
fn write_block(&mut self, buffer: &[u8]) -> Result<bool, io::Error> {
|
||||||
|
|
||||||
if buffer.len() != PROXMOX_TAPE_BLOCK_SIZE {
|
if buffer.len() != PROXMOX_TAPE_BLOCK_SIZE {
|
||||||
proxmox::io_bail!("EmulateTapeWriter: got write with wrong block size ({} != {}",
|
proxmox_sys::io_bail!("EmulateTapeWriter: got write with wrong block size ({} != {}",
|
||||||
buffer.len(), PROXMOX_TAPE_BLOCK_SIZE);
|
buffer.len(), PROXMOX_TAPE_BLOCK_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ impl <W: Write> BlockWrite for EmulateTapeWriter<W> {
|
||||||
|
|
||||||
fn write_filemark(&mut self) -> Result<(), std::io::Error> {
|
fn write_filemark(&mut self) -> Result<(), std::io::Error> {
|
||||||
if self.wrote_eof {
|
if self.wrote_eof {
|
||||||
proxmox::io_bail!("EmulateTapeWriter: detected multiple EOF writes");
|
proxmox_sys::io_bail!("EmulateTapeWriter: detected multiple EOF writes");
|
||||||
}
|
}
|
||||||
// do nothing, just record the call
|
// do nothing, just record the call
|
||||||
self.wrote_eof = true;
|
self.wrote_eof = true;
|
||||||
|
|
|
@ -7,9 +7,9 @@ use std::os::unix::io::AsRawFd;
|
||||||
use anyhow::{bail, format_err, Error};
|
use anyhow::{bail, format_err, Error};
|
||||||
use nix::fcntl::{fcntl, FcntlArg, OFlag};
|
use nix::fcntl::{fcntl, FcntlArg, OFlag};
|
||||||
|
|
||||||
use proxmox::sys::error::SysResult;
|
use proxmox_sys::error::SysResult;
|
||||||
|
use proxmox_sys::fs::scan_subdir;
|
||||||
|
|
||||||
use pbs_tools::fs::scan_subdir;
|
|
||||||
use pbs_api_types::{DeviceKind, OptionalDeviceIdentification, TapeDeviceInfo};
|
use pbs_api_types::{DeviceKind, OptionalDeviceIdentification, TapeDeviceInfo};
|
||||||
|
|
||||||
lazy_static::lazy_static!{
|
lazy_static::lazy_static!{
|
||||||
|
|
|
@ -25,7 +25,7 @@ pub use mam::*;
|
||||||
mod report_density;
|
mod report_density;
|
||||||
pub use report_density::*;
|
pub use report_density::*;
|
||||||
|
|
||||||
use proxmox::sys::error::SysResult;
|
use proxmox_sys::error::SysResult;
|
||||||
use proxmox_io::{ReadExt, WriteExt};
|
use proxmox_io::{ReadExt, WriteExt};
|
||||||
|
|
||||||
use pbs_api_types::{MamAttribute, Lp17VolumeStatistics, LtoDriveAndMediaStatus};
|
use pbs_api_types::{MamAttribute, Lp17VolumeStatistics, LtoDriveAndMediaStatus};
|
||||||
|
@ -530,11 +530,11 @@ impl SgTape {
|
||||||
) -> Result<(), std::io::Error> {
|
) -> Result<(), std::io::Error> {
|
||||||
|
|
||||||
if count > 255 {
|
if count > 255 {
|
||||||
proxmox::io_bail!("write_filemarks failed: got strange count '{}'", count);
|
proxmox_sys::io_bail!("write_filemarks failed: got strange count '{}'", count);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut sg_raw = SgRaw::new(&mut self.file, 16)
|
let mut sg_raw = SgRaw::new(&mut self.file, 16)
|
||||||
.map_err(|err| proxmox::io_format_err!("write_filemarks failed (alloc) - {}", err))?;
|
.map_err(|err| proxmox_sys::io_format_err!("write_filemarks failed (alloc) - {}", err))?;
|
||||||
|
|
||||||
sg_raw.set_timeout(Self::SCSI_TAPE_DEFAULT_TIMEOUT);
|
sg_raw.set_timeout(Self::SCSI_TAPE_DEFAULT_TIMEOUT);
|
||||||
let mut cmd = Vec::new();
|
let mut cmd = Vec::new();
|
||||||
|
@ -553,7 +553,7 @@ impl SgTape {
|
||||||
/* LEOM - ignore */
|
/* LEOM - ignore */
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
proxmox::io_bail!("write filemark failed - {}", err);
|
proxmox_sys::io_bail!("write filemark failed - {}", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -632,7 +632,7 @@ impl SgTape {
|
||||||
let transfer_len = data.len();
|
let transfer_len = data.len();
|
||||||
|
|
||||||
if transfer_len > 0x800000 {
|
if transfer_len > 0x800000 {
|
||||||
proxmox::io_bail!("write failed - data too large");
|
proxmox_sys::io_bail!("write failed - data too large");
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut sg_raw = SgRaw::new(&mut self.file, 0)
|
let mut sg_raw = SgRaw::new(&mut self.file, 0)
|
||||||
|
@ -656,7 +656,7 @@ impl SgTape {
|
||||||
return Ok(true); // LEOM
|
return Ok(true); // LEOM
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
proxmox::io_bail!("write failed - {}", err);
|
proxmox_sys::io_bail!("write failed - {}", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -666,7 +666,7 @@ impl SgTape {
|
||||||
|
|
||||||
if transfer_len > 0xFFFFFF {
|
if transfer_len > 0xFFFFFF {
|
||||||
return Err(BlockReadError::Error(
|
return Err(BlockReadError::Error(
|
||||||
proxmox::io_format_err!("read failed - buffer too large")
|
proxmox_sys::io_format_err!("read failed - buffer too large")
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -693,14 +693,14 @@ impl SgTape {
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
return Err(BlockReadError::Error(
|
return Err(BlockReadError::Error(
|
||||||
proxmox::io_format_err!("read failed - {}", err)
|
proxmox_sys::io_format_err!("read failed - {}", err)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if data.len() != transfer_len {
|
if data.len() != transfer_len {
|
||||||
return Err(BlockReadError::Error(
|
return Err(BlockReadError::Error(
|
||||||
proxmox::io_format_err!("read failed - unexpected block len ({} != {})", data.len(), buffer.len())
|
proxmox_sys::io_format_err!("read failed - unexpected block len ({} != {})", data.len(), buffer.len())
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -951,7 +951,7 @@ impl <'a> BlockRead for SgTapeReader<'a> {
|
||||||
|
|
||||||
fn read_block(&mut self, buffer: &mut [u8]) -> Result<usize, BlockReadError> {
|
fn read_block(&mut self, buffer: &mut [u8]) -> Result<usize, BlockReadError> {
|
||||||
if self.end_of_file {
|
if self.end_of_file {
|
||||||
return Err(BlockReadError::Error(proxmox::io_format_err!("detected read after EOF!")));
|
return Err(BlockReadError::Error(proxmox_sys::io_format_err!("detected read after EOF!")));
|
||||||
}
|
}
|
||||||
match self.sg_tape.read_block(buffer) {
|
match self.sg_tape.read_block(buffer) {
|
||||||
Ok(usize) => Ok(usize),
|
Ok(usize) => Ok(usize),
|
||||||
|
|
|
@ -175,7 +175,7 @@ fn decode_mam_attributes(data: &[u8]) -> Result<Vec<MamAttribute>, Error> {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
MamFormat::BINARY => proxmox::tools::digest_to_hex(&data),
|
MamFormat::BINARY => hex::encode(&data),
|
||||||
};
|
};
|
||||||
list.push(MamAttribute {
|
list.push(MamAttribute {
|
||||||
id: head_id,
|
id: head_id,
|
||||||
|
|
|
@ -34,7 +34,7 @@ pub trait TapeWrite {
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Result<bool, std::io::Error> {
|
) -> Result<bool, std::io::Error> {
|
||||||
if header.size as usize != data.len() {
|
if header.size as usize != data.len() {
|
||||||
proxmox::io_bail!("write_header with wrong size - internal error");
|
proxmox_sys::io_bail!("write_header with wrong size - internal error");
|
||||||
}
|
}
|
||||||
let header = header.to_le();
|
let header = header.to_le();
|
||||||
|
|
||||||
|
|
|
@ -32,12 +32,13 @@ url = "2.1"
|
||||||
walkdir = "2"
|
walkdir = "2"
|
||||||
zstd = { version = "0.6", features = [ "bindgen" ] }
|
zstd = { version = "0.6", features = [ "bindgen" ] }
|
||||||
|
|
||||||
proxmox = { version = "0.15.3", default-features = false, features = [ "tokio" ] }
|
#proxmox = { version = "0.15.3", default-features = false, features = [ "tokio" ] }
|
||||||
proxmox-async = "0.2"
|
proxmox-async = "0.3"
|
||||||
proxmox-borrow = "1"
|
proxmox-borrow = "1"
|
||||||
proxmox-io = { version = "1", features = [ "tokio" ] }
|
proxmox-io = { version = "1", features = [ "tokio" ] }
|
||||||
proxmox-lang = { version = "1" }
|
proxmox-lang = { version = "1" }
|
||||||
proxmox-time = { version = "1" }
|
proxmox-time = { version = "1" }
|
||||||
|
proxmox-sys = "0.2"
|
||||||
|
|
||||||
pbs-buildcfg = { path = "../pbs-buildcfg" }
|
pbs-buildcfg = { path = "../pbs-buildcfg" }
|
||||||
pbs-api-types = { path = "../pbs-api-types" }
|
pbs-api-types = { path = "../pbs-api-types" }
|
||||||
|
|
|
@ -1,334 +0,0 @@
|
||||||
//! Implementation of the calls to handle POSIX access control lists
|
|
||||||
|
|
||||||
// see C header file <sys/acl.h> for reference
|
|
||||||
extern crate libc;
|
|
||||||
|
|
||||||
use std::ffi::CString;
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::os::unix::ffi::OsStrExt;
|
|
||||||
use std::os::unix::io::RawFd;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::ptr;
|
|
||||||
|
|
||||||
use libc::{c_char, c_int, c_uint, c_void};
|
|
||||||
use nix::errno::Errno;
|
|
||||||
use nix::NixPath;
|
|
||||||
|
|
||||||
// from: acl/include/acl.h
|
|
||||||
pub const ACL_UNDEFINED_ID: u32 = 0xffffffff;
|
|
||||||
// acl_perm_t values
|
|
||||||
pub type ACLPerm = c_uint;
|
|
||||||
pub const ACL_READ: ACLPerm = 0x04;
|
|
||||||
pub const ACL_WRITE: ACLPerm = 0x02;
|
|
||||||
pub const ACL_EXECUTE: ACLPerm = 0x01;
|
|
||||||
|
|
||||||
// acl_tag_t values
|
|
||||||
pub type ACLTag = c_int;
|
|
||||||
pub const ACL_UNDEFINED_TAG: ACLTag = 0x00;
|
|
||||||
pub const ACL_USER_OBJ: ACLTag = 0x01;
|
|
||||||
pub const ACL_USER: ACLTag = 0x02;
|
|
||||||
pub const ACL_GROUP_OBJ: ACLTag = 0x04;
|
|
||||||
pub const ACL_GROUP: ACLTag = 0x08;
|
|
||||||
pub const ACL_MASK: ACLTag = 0x10;
|
|
||||||
pub const ACL_OTHER: ACLTag = 0x20;
|
|
||||||
|
|
||||||
// acl_type_t values
|
|
||||||
pub type ACLType = c_uint;
|
|
||||||
pub const ACL_TYPE_ACCESS: ACLType = 0x8000;
|
|
||||||
pub const ACL_TYPE_DEFAULT: ACLType = 0x4000;
|
|
||||||
|
|
||||||
// acl entry constants
|
|
||||||
pub const ACL_FIRST_ENTRY: c_int = 0;
|
|
||||||
pub const ACL_NEXT_ENTRY: c_int = 1;
|
|
||||||
|
|
||||||
// acl to extended attribute names constants
|
|
||||||
// from: acl/include/acl_ea.h
|
|
||||||
pub const ACL_EA_ACCESS: &str = "system.posix_acl_access";
|
|
||||||
pub const ACL_EA_DEFAULT: &str = "system.posix_acl_default";
|
|
||||||
pub const ACL_EA_VERSION: u32 = 0x0002;
|
|
||||||
|
|
||||||
#[link(name = "acl")]
|
|
||||||
extern "C" {
|
|
||||||
fn acl_get_file(path: *const c_char, acl_type: ACLType) -> *mut c_void;
|
|
||||||
fn acl_set_file(path: *const c_char, acl_type: ACLType, acl: *mut c_void) -> c_int;
|
|
||||||
fn acl_get_fd(fd: RawFd) -> *mut c_void;
|
|
||||||
fn acl_get_entry(acl: *const c_void, entry_id: c_int, entry: *mut *mut c_void) -> c_int;
|
|
||||||
fn acl_create_entry(acl: *mut *mut c_void, entry: *mut *mut c_void) -> c_int;
|
|
||||||
fn acl_get_tag_type(entry: *mut c_void, tag_type: *mut ACLTag) -> c_int;
|
|
||||||
fn acl_set_tag_type(entry: *mut c_void, tag_type: ACLTag) -> c_int;
|
|
||||||
fn acl_get_permset(entry: *mut c_void, permset: *mut *mut c_void) -> c_int;
|
|
||||||
fn acl_clear_perms(permset: *mut c_void) -> c_int;
|
|
||||||
fn acl_get_perm(permset: *mut c_void, perm: ACLPerm) -> c_int;
|
|
||||||
fn acl_add_perm(permset: *mut c_void, perm: ACLPerm) -> c_int;
|
|
||||||
fn acl_get_qualifier(entry: *mut c_void) -> *mut c_void;
|
|
||||||
fn acl_set_qualifier(entry: *mut c_void, qualifier: *const c_void) -> c_int;
|
|
||||||
fn acl_init(count: c_int) -> *mut c_void;
|
|
||||||
fn acl_valid(ptr: *const c_void) -> c_int;
|
|
||||||
fn acl_free(ptr: *mut c_void) -> c_int;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ACL {
|
|
||||||
ptr: *mut c_void,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for ACL {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
let ret = unsafe { acl_free(self.ptr) };
|
|
||||||
if ret != 0 {
|
|
||||||
panic!("invalid pointer encountered while dropping ACL - {}", Errno::last());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ACL {
|
|
||||||
pub fn init(count: usize) -> Result<ACL, nix::errno::Errno> {
|
|
||||||
let ptr = unsafe { acl_init(count as i32 as c_int) };
|
|
||||||
if ptr.is_null() {
|
|
||||||
return Err(Errno::last());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(ACL { ptr })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_file<P: AsRef<Path>>(path: P, acl_type: ACLType) -> Result<ACL, nix::errno::Errno> {
|
|
||||||
let path_cstr = CString::new(path.as_ref().as_os_str().as_bytes()).unwrap();
|
|
||||||
let ptr = unsafe { acl_get_file(path_cstr.as_ptr(), acl_type) };
|
|
||||||
if ptr.is_null() {
|
|
||||||
return Err(Errno::last());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(ACL { ptr })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_file<P: NixPath + ?Sized>(&self, path: &P, acl_type: ACLType) -> nix::Result<()> {
|
|
||||||
path.with_nix_path(|path| {
|
|
||||||
Errno::result(unsafe { acl_set_file(path.as_ptr(), acl_type, self.ptr) })
|
|
||||||
})?
|
|
||||||
.map(drop)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_fd(fd: RawFd) -> Result<ACL, nix::errno::Errno> {
|
|
||||||
let ptr = unsafe { acl_get_fd(fd) };
|
|
||||||
if ptr.is_null() {
|
|
||||||
return Err(Errno::last());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(ACL { ptr })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_entry(&mut self) -> Result<ACLEntry, nix::errno::Errno> {
|
|
||||||
let mut ptr = ptr::null_mut() as *mut c_void;
|
|
||||||
let res = unsafe { acl_create_entry(&mut self.ptr, &mut ptr) };
|
|
||||||
if res < 0 {
|
|
||||||
return Err(Errno::last());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(ACLEntry {
|
|
||||||
ptr,
|
|
||||||
_phantom: PhantomData,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_valid(&self) -> bool {
|
|
||||||
let res = unsafe { acl_valid(self.ptr) };
|
|
||||||
if res == 0 {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn entries(self) -> ACLEntriesIterator {
|
|
||||||
ACLEntriesIterator {
|
|
||||||
acl: self,
|
|
||||||
current: ACL_FIRST_ENTRY,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_entry_full(&mut self, tag: ACLTag, qualifier: Option<u64>, permissions: u64)
|
|
||||||
-> Result<(), nix::errno::Errno>
|
|
||||||
{
|
|
||||||
let mut entry = self.create_entry()?;
|
|
||||||
entry.set_tag_type(tag)?;
|
|
||||||
if let Some(qualifier) = qualifier {
|
|
||||||
entry.set_qualifier(qualifier)?;
|
|
||||||
}
|
|
||||||
entry.set_permissions(permissions)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ACLEntry<'a> {
|
|
||||||
ptr: *mut c_void,
|
|
||||||
_phantom: PhantomData<&'a mut ()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ACLEntry<'a> {
|
|
||||||
pub fn get_tag_type(&self) -> Result<ACLTag, nix::errno::Errno> {
|
|
||||||
let mut tag = ACL_UNDEFINED_TAG;
|
|
||||||
let res = unsafe { acl_get_tag_type(self.ptr, &mut tag as *mut ACLTag) };
|
|
||||||
if res < 0 {
|
|
||||||
return Err(Errno::last());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_tag_type(&mut self, tag: ACLTag) -> Result<(), nix::errno::Errno> {
|
|
||||||
let res = unsafe { acl_set_tag_type(self.ptr, tag) };
|
|
||||||
if res < 0 {
|
|
||||||
return Err(Errno::last());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_permissions(&self) -> Result<u64, nix::errno::Errno> {
|
|
||||||
let mut permissions = 0;
|
|
||||||
let mut permset = ptr::null_mut() as *mut c_void;
|
|
||||||
let mut res = unsafe { acl_get_permset(self.ptr, &mut permset) };
|
|
||||||
if res < 0 {
|
|
||||||
return Err(Errno::last());
|
|
||||||
}
|
|
||||||
|
|
||||||
for &perm in &[ACL_READ, ACL_WRITE, ACL_EXECUTE] {
|
|
||||||
res = unsafe { acl_get_perm(permset, perm) };
|
|
||||||
if res < 0 {
|
|
||||||
return Err(Errno::last());
|
|
||||||
}
|
|
||||||
|
|
||||||
if res == 1 {
|
|
||||||
permissions |= perm as u64;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(permissions)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_permissions(&mut self, permissions: u64) -> Result<u64, nix::errno::Errno> {
|
|
||||||
let mut permset = ptr::null_mut() as *mut c_void;
|
|
||||||
let mut res = unsafe { acl_get_permset(self.ptr, &mut permset) };
|
|
||||||
if res < 0 {
|
|
||||||
return Err(Errno::last());
|
|
||||||
}
|
|
||||||
|
|
||||||
res = unsafe { acl_clear_perms(permset) };
|
|
||||||
if res < 0 {
|
|
||||||
return Err(Errno::last());
|
|
||||||
}
|
|
||||||
|
|
||||||
for &perm in &[ACL_READ, ACL_WRITE, ACL_EXECUTE] {
|
|
||||||
if permissions & perm as u64 == perm as u64 {
|
|
||||||
res = unsafe { acl_add_perm(permset, perm) };
|
|
||||||
if res < 0 {
|
|
||||||
return Err(Errno::last());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(permissions)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_qualifier(&self) -> Result<u64, nix::errno::Errno> {
|
|
||||||
let qualifier = unsafe { acl_get_qualifier(self.ptr) };
|
|
||||||
if qualifier.is_null() {
|
|
||||||
return Err(Errno::last());
|
|
||||||
}
|
|
||||||
let result = unsafe { *(qualifier as *const u32) as u64 };
|
|
||||||
let ret = unsafe { acl_free(qualifier) };
|
|
||||||
if ret != 0 {
|
|
||||||
panic!("invalid pointer encountered while dropping ACL qualifier - {}", Errno::last());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_qualifier(&mut self, qualifier: u64) -> Result<(), nix::errno::Errno> {
|
|
||||||
let val = qualifier as u32;
|
|
||||||
let val_ptr: *const u32 = &val;
|
|
||||||
let res = unsafe { acl_set_qualifier(self.ptr, val_ptr as *const c_void) };
|
|
||||||
if res < 0 {
|
|
||||||
return Err(Errno::last());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ACLEntriesIterator {
|
|
||||||
acl: ACL,
|
|
||||||
current: c_int,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for &'a mut ACLEntriesIterator {
|
|
||||||
type Item = ACLEntry<'a>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
let mut entry_ptr = ptr::null_mut();
|
|
||||||
let res = unsafe { acl_get_entry(self.acl.ptr, self.current, &mut entry_ptr) };
|
|
||||||
self.current = ACL_NEXT_ENTRY;
|
|
||||||
if res == 1 {
|
|
||||||
return Some(ACLEntry { ptr: entry_ptr, _phantom: PhantomData });
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Helper to transform `PxarEntry`s user mode to acl permissions.
|
|
||||||
pub fn mode_user_to_acl_permissions(mode: u64) -> u64 {
|
|
||||||
(mode >> 6) & 7
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Helper to transform `PxarEntry`s group mode to acl permissions.
|
|
||||||
pub fn mode_group_to_acl_permissions(mode: u64) -> u64 {
|
|
||||||
(mode >> 3) & 7
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Helper to transform `PxarEntry`s other mode to acl permissions.
|
|
||||||
pub fn mode_other_to_acl_permissions(mode: u64) -> u64 {
|
|
||||||
mode & 7
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Buffer to compose ACLs as extended attribute.
|
|
||||||
pub struct ACLXAttrBuffer {
|
|
||||||
buffer: Vec<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ACLXAttrBuffer {
|
|
||||||
/// Create a new buffer to write ACLs as extended attribute.
|
|
||||||
///
|
|
||||||
/// `version` defines the ACL_EA_VERSION found in acl/include/acl_ea.h
|
|
||||||
pub fn new(version: u32) -> Self {
|
|
||||||
let mut buffer = Vec::new();
|
|
||||||
buffer.extend_from_slice(&version.to_le_bytes());
|
|
||||||
Self { buffer }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add ACL entry to buffer.
|
|
||||||
pub fn add_entry(&mut self, tag: ACLTag, qualifier: Option<u64>, permissions: u64) {
|
|
||||||
self.buffer.extend_from_slice(&(tag as u16).to_le_bytes());
|
|
||||||
self.buffer.extend_from_slice(&(permissions as u16).to_le_bytes());
|
|
||||||
match qualifier {
|
|
||||||
Some(qualifier) => self.buffer.extend_from_slice(&(qualifier as u32).to_le_bytes()),
|
|
||||||
None => self.buffer.extend_from_slice(&ACL_UNDEFINED_ID.to_le_bytes()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Length of the buffer in bytes.
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.buffer.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The buffer always contains at least the version, it is never empty
|
|
||||||
pub const fn is_empty(&self) -> bool { false }
|
|
||||||
|
|
||||||
/// Borrow raw buffer as mut slice.
|
|
||||||
pub fn as_mut_slice(&mut self) -> &mut [u8] {
|
|
||||||
self.buffer.as_mut_slice()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -41,7 +41,7 @@ fn x509name_to_string(name: &openssl::x509::X509NameRef) -> Result<String, Error
|
||||||
|
|
||||||
impl CertInfo {
|
impl CertInfo {
|
||||||
pub fn from_path(path: PathBuf) -> Result<Self, Error> {
|
pub fn from_path(path: PathBuf) -> Result<Self, Error> {
|
||||||
Self::from_pem(&proxmox::tools::fs::file_get_contents(&path)?)
|
Self::from_pem(&proxmox_sys::fs::file_get_contents(&path)?)
|
||||||
.map_err(|err| format_err!("failed to load certificate from {:?} - {}", path, err))
|
.map_err(|err| format_err!("failed to load certificate from {:?} - {}", path, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
use anyhow::{bail, format_err, Error};
|
|
||||||
|
|
||||||
/// Helper to check result from std::process::Command output
|
|
||||||
///
|
|
||||||
/// The exit_code_check() function should return true if the exit code
|
|
||||||
/// is considered successful.
|
|
||||||
pub fn command_output(
|
|
||||||
output: std::process::Output,
|
|
||||||
exit_code_check: Option<fn(i32) -> bool>,
|
|
||||||
) -> Result<Vec<u8>, Error> {
|
|
||||||
if !output.status.success() {
|
|
||||||
match output.status.code() {
|
|
||||||
Some(code) => {
|
|
||||||
let is_ok = match exit_code_check {
|
|
||||||
Some(check_fn) => check_fn(code),
|
|
||||||
None => code == 0,
|
|
||||||
};
|
|
||||||
if !is_ok {
|
|
||||||
let msg = String::from_utf8(output.stderr)
|
|
||||||
.map(|m| {
|
|
||||||
if m.is_empty() {
|
|
||||||
String::from("no error message")
|
|
||||||
} else {
|
|
||||||
m
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|_| String::from("non utf8 error message (suppressed)"));
|
|
||||||
|
|
||||||
bail!("status code: {} - {}", code, msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => bail!("terminated by signal"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(output.stdout)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Helper to check result from std::process::Command output, returns String.
|
|
||||||
///
|
|
||||||
/// The exit_code_check() function should return true if the exit code
|
|
||||||
/// is considered successful.
|
|
||||||
pub fn command_output_as_string(
|
|
||||||
output: std::process::Output,
|
|
||||||
exit_code_check: Option<fn(i32) -> bool>,
|
|
||||||
) -> Result<String, Error> {
|
|
||||||
let output = command_output(output, exit_code_check)?;
|
|
||||||
let output = String::from_utf8(output)?;
|
|
||||||
Ok(output)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_command(
|
|
||||||
mut command: std::process::Command,
|
|
||||||
exit_code_check: Option<fn(i32) -> bool>,
|
|
||||||
) -> Result<String, Error> {
|
|
||||||
let output = command
|
|
||||||
.output()
|
|
||||||
.map_err(|err| format_err!("failed to execute {:?} - {}", command, err))?;
|
|
||||||
|
|
||||||
let output = command_output_as_string(output, exit_code_check)
|
|
||||||
.map_err(|err| format_err!("command {:?} failed - {}", command, err))?;
|
|
||||||
|
|
||||||
Ok(output)
|
|
||||||
}
|
|
|
@ -1,372 +0,0 @@
|
||||||
//! File system helper utilities.
|
|
||||||
|
|
||||||
use std::borrow::{Borrow, BorrowMut};
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::{self, BufRead};
|
|
||||||
use std::ops::{Deref, DerefMut};
|
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use anyhow::{bail, format_err, Error};
|
|
||||||
use nix::dir;
|
|
||||||
use nix::dir::Dir;
|
|
||||||
use nix::fcntl::OFlag;
|
|
||||||
use nix::sys::stat::Mode;
|
|
||||||
|
|
||||||
use regex::Regex;
|
|
||||||
|
|
||||||
use proxmox::sys::error::SysError;
|
|
||||||
use proxmox_borrow::Tied;
|
|
||||||
|
|
||||||
pub type DirLockGuard = Dir;
|
|
||||||
|
|
||||||
/// This wraps nix::dir::Entry with the parent directory's file descriptor.
|
|
||||||
pub struct ReadDirEntry {
|
|
||||||
entry: dir::Entry,
|
|
||||||
parent_fd: RawFd,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<dir::Entry> for ReadDirEntry {
|
|
||||||
fn into(self) -> dir::Entry {
|
|
||||||
self.entry
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for ReadDirEntry {
|
|
||||||
type Target = dir::Entry;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.entry
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for ReadDirEntry {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.entry
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRef<dir::Entry> for ReadDirEntry {
|
|
||||||
fn as_ref(&self) -> &dir::Entry {
|
|
||||||
&self.entry
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsMut<dir::Entry> for ReadDirEntry {
|
|
||||||
fn as_mut(&mut self) -> &mut dir::Entry {
|
|
||||||
&mut self.entry
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Borrow<dir::Entry> for ReadDirEntry {
|
|
||||||
fn borrow(&self) -> &dir::Entry {
|
|
||||||
&self.entry
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BorrowMut<dir::Entry> for ReadDirEntry {
|
|
||||||
fn borrow_mut(&mut self) -> &mut dir::Entry {
|
|
||||||
&mut self.entry
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ReadDirEntry {
|
|
||||||
#[inline]
|
|
||||||
pub fn parent_fd(&self) -> RawFd {
|
|
||||||
self.parent_fd
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn file_name_utf8_unchecked(&self) -> &str {
|
|
||||||
std::str::from_utf8_unchecked(self.file_name().to_bytes())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since Tied<T, U> implements Deref to U, a Tied<Dir, Iterator> already implements Iterator.
|
|
||||||
// This is simply a wrapper with a shorter type name mapping nix::Error to anyhow::Error.
|
|
||||||
/// Wrapper over a pair of `nix::dir::Dir` and `nix::dir::Iter`, returned by `read_subdir()`.
|
|
||||||
pub struct ReadDir {
|
|
||||||
iter: Tied<Dir, dyn Iterator<Item = nix::Result<dir::Entry>> + Send>,
|
|
||||||
dir_fd: RawFd,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator for ReadDir {
|
|
||||||
type Item = Result<ReadDirEntry, Error>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
self.iter.next().map(|res| {
|
|
||||||
res.map(|entry| ReadDirEntry { entry, parent_fd: self.dir_fd })
|
|
||||||
.map_err(Error::from)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create an iterator over sub directory entries.
|
|
||||||
/// This uses `openat` on `dirfd`, so `path` can be relative to that or an absolute path.
|
|
||||||
pub fn read_subdir<P: ?Sized + nix::NixPath>(dirfd: RawFd, path: &P) -> nix::Result<ReadDir> {
|
|
||||||
let dir = Dir::openat(dirfd, path, OFlag::O_RDONLY, Mode::empty())?;
|
|
||||||
let fd = dir.as_raw_fd();
|
|
||||||
let iter = Tied::new(dir, |dir| {
|
|
||||||
Box::new(unsafe { (*dir).iter() })
|
|
||||||
as Box<dyn Iterator<Item = nix::Result<dir::Entry>> + Send>
|
|
||||||
});
|
|
||||||
Ok(ReadDir { iter, dir_fd: fd })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Scan through a directory with a regular expression. This is simply a shortcut filtering the
|
|
||||||
/// results of `read_subdir`. Non-UTF8 compatible file names are silently ignored.
|
|
||||||
pub fn scan_subdir<'a, P: ?Sized + nix::NixPath>(
|
|
||||||
dirfd: RawFd,
|
|
||||||
path: &P,
|
|
||||||
regex: &'a regex::Regex,
|
|
||||||
) -> Result<impl Iterator<Item = Result<ReadDirEntry, Error>> + 'a, nix::Error> {
|
|
||||||
Ok(read_subdir(dirfd, path)?.filter_file_name_regex(regex))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Scan directory for matching file names with a callback.
|
|
||||||
///
|
|
||||||
/// Scan through all directory entries and call `callback()` function
|
|
||||||
/// if the entry name matches the regular expression. This function
|
|
||||||
/// used unix `openat()`, so you can pass absolute or relative file
|
|
||||||
/// names. This function simply skips non-UTF8 encoded names.
|
|
||||||
pub fn scandir<P, F>(
|
|
||||||
dirfd: RawFd,
|
|
||||||
path: &P,
|
|
||||||
regex: ®ex::Regex,
|
|
||||||
mut callback: F,
|
|
||||||
) -> Result<(), Error>
|
|
||||||
where
|
|
||||||
F: FnMut(RawFd, &str, nix::dir::Type) -> Result<(), Error>,
|
|
||||||
P: ?Sized + nix::NixPath,
|
|
||||||
{
|
|
||||||
for entry in scan_subdir(dirfd, path, regex)? {
|
|
||||||
let entry = entry?;
|
|
||||||
let file_type = match entry.file_type() {
|
|
||||||
Some(file_type) => file_type,
|
|
||||||
None => bail!("unable to detect file type"),
|
|
||||||
};
|
|
||||||
|
|
||||||
callback(
|
|
||||||
entry.parent_fd(),
|
|
||||||
unsafe { entry.file_name_utf8_unchecked() },
|
|
||||||
file_type,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Helper trait to provide a combinators for directory entry iterators.
|
|
||||||
pub trait FileIterOps<T, E>
|
|
||||||
where
|
|
||||||
Self: Sized + Iterator<Item = Result<T, E>>,
|
|
||||||
T: Borrow<dir::Entry>,
|
|
||||||
E: Into<Error> + Send + Sync,
|
|
||||||
{
|
|
||||||
/// Filter by file type. This is more convenient than using the `filter` method alone as this
|
|
||||||
/// also includes error handling and handling of files without a type (via an error).
|
|
||||||
fn filter_file_type(self, ty: dir::Type) -> FileTypeFilter<Self, T, E> {
|
|
||||||
FileTypeFilter { inner: self, ty }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Filter by file name. Note that file names which aren't valid utf-8 will be treated as if
|
|
||||||
/// they do not match the pattern.
|
|
||||||
fn filter_file_name_regex(self, regex: &Regex) -> FileNameRegexFilter<Self, T, E> {
|
|
||||||
FileNameRegexFilter { inner: self, regex }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, T, E> FileIterOps<T, E> for I
|
|
||||||
where
|
|
||||||
I: Iterator<Item = Result<T, E>>,
|
|
||||||
T: Borrow<dir::Entry>,
|
|
||||||
E: Into<Error> + Send + Sync,
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This filters files from its inner iterator by a file type. Files with no type produce an error.
|
|
||||||
pub struct FileTypeFilter<I, T, E>
|
|
||||||
where
|
|
||||||
I: Iterator<Item = Result<T, E>>,
|
|
||||||
T: Borrow<dir::Entry>,
|
|
||||||
E: Into<Error> + Send + Sync,
|
|
||||||
{
|
|
||||||
inner: I,
|
|
||||||
ty: nix::dir::Type,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, T, E> Iterator for FileTypeFilter<I, T, E>
|
|
||||||
where
|
|
||||||
I: Iterator<Item = Result<T, E>>,
|
|
||||||
T: Borrow<dir::Entry>,
|
|
||||||
E: Into<Error> + Send + Sync,
|
|
||||||
{
|
|
||||||
type Item = Result<T, Error>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
loop {
|
|
||||||
let item = self.inner.next()?.map_err(|e| e.into());
|
|
||||||
match item {
|
|
||||||
Ok(ref entry) => match entry.borrow().file_type() {
|
|
||||||
Some(ty) => {
|
|
||||||
if ty == self.ty {
|
|
||||||
return Some(item);
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => return Some(Err(format_err!("unable to detect file type"))),
|
|
||||||
},
|
|
||||||
Err(_) => return Some(item),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This filters files by name via a Regex. Files whose file name aren't valid utf-8 are skipped
|
|
||||||
/// silently.
|
|
||||||
pub struct FileNameRegexFilter<'a, I, T, E>
|
|
||||||
where
|
|
||||||
I: Iterator<Item = Result<T, E>>,
|
|
||||||
T: Borrow<dir::Entry>,
|
|
||||||
{
|
|
||||||
inner: I,
|
|
||||||
regex: &'a Regex,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, T, E> Iterator for FileNameRegexFilter<'_, I, T, E>
|
|
||||||
where
|
|
||||||
I: Iterator<Item = Result<T, E>>,
|
|
||||||
T: Borrow<dir::Entry>,
|
|
||||||
{
|
|
||||||
type Item = Result<T, E>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
loop {
|
|
||||||
let item = self.inner.next()?;
|
|
||||||
match item {
|
|
||||||
Ok(ref entry) => {
|
|
||||||
if let Ok(name) = entry.borrow().file_name().to_str() {
|
|
||||||
if self.regex.is_match(name) {
|
|
||||||
return Some(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// file did not match regex or isn't valid utf-8
|
|
||||||
continue;
|
|
||||||
},
|
|
||||||
Err(_) => return Some(item),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// /usr/include/linux/fs.h: #define FS_IOC_GETFLAGS _IOR('f', 1, long)
|
|
||||||
// read Linux file system attributes (see man chattr)
|
|
||||||
nix::ioctl_read!(read_attr_fd, b'f', 1, libc::c_long);
|
|
||||||
nix::ioctl_write_ptr!(write_attr_fd, b'f', 2, libc::c_long);
|
|
||||||
|
|
||||||
// /usr/include/linux/msdos_fs.h: #define FAT_IOCTL_GET_ATTRIBUTES _IOR('r', 0x10, __u32)
|
|
||||||
// read FAT file system attributes
|
|
||||||
nix::ioctl_read!(read_fat_attr_fd, b'r', 0x10, u32);
|
|
||||||
nix::ioctl_write_ptr!(write_fat_attr_fd, b'r', 0x11, u32);
|
|
||||||
|
|
||||||
// From /usr/include/linux/fs.h
|
|
||||||
// #define FS_IOC_FSGETXATTR _IOR('X', 31, struct fsxattr)
|
|
||||||
// #define FS_IOC_FSSETXATTR _IOW('X', 32, struct fsxattr)
|
|
||||||
nix::ioctl_read!(fs_ioc_fsgetxattr, b'X', 31, FSXAttr);
|
|
||||||
nix::ioctl_write_ptr!(fs_ioc_fssetxattr, b'X', 32, FSXAttr);
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct FSXAttr {
|
|
||||||
pub fsx_xflags: u32,
|
|
||||||
pub fsx_extsize: u32,
|
|
||||||
pub fsx_nextents: u32,
|
|
||||||
pub fsx_projid: u32,
|
|
||||||
pub fsx_cowextsize: u32,
|
|
||||||
pub fsx_pad: [u8; 8],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for FSXAttr {
|
|
||||||
fn default() -> Self {
|
|
||||||
FSXAttr {
|
|
||||||
fsx_xflags: 0u32,
|
|
||||||
fsx_extsize: 0u32,
|
|
||||||
fsx_nextents: 0u32,
|
|
||||||
fsx_projid: 0u32,
|
|
||||||
fsx_cowextsize: 0u32,
|
|
||||||
fsx_pad: [0u8; 8],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Attempt to acquire a shared flock on the given path, 'what' and
|
|
||||||
/// 'would_block_message' are used for error formatting.
|
|
||||||
pub fn lock_dir_noblock_shared(
|
|
||||||
path: &std::path::Path,
|
|
||||||
what: &str,
|
|
||||||
would_block_msg: &str,
|
|
||||||
) -> Result<DirLockGuard, Error> {
|
|
||||||
do_lock_dir_noblock(path, what, would_block_msg, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Attempt to acquire an exclusive flock on the given path, 'what' and
|
|
||||||
/// 'would_block_message' are used for error formatting.
|
|
||||||
pub fn lock_dir_noblock(
|
|
||||||
path: &std::path::Path,
|
|
||||||
what: &str,
|
|
||||||
would_block_msg: &str,
|
|
||||||
) -> Result<DirLockGuard, Error> {
|
|
||||||
do_lock_dir_noblock(path, what, would_block_msg, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_lock_dir_noblock(
|
|
||||||
path: &std::path::Path,
|
|
||||||
what: &str,
|
|
||||||
would_block_msg: &str,
|
|
||||||
exclusive: bool,
|
|
||||||
) -> Result<DirLockGuard, Error> {
|
|
||||||
let mut handle = Dir::open(path, OFlag::O_RDONLY, Mode::empty())
|
|
||||||
.map_err(|err| {
|
|
||||||
format_err!("unable to open {} directory {:?} for locking - {}", what, path, err)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// acquire in non-blocking mode, no point in waiting here since other
|
|
||||||
// backups could still take a very long time
|
|
||||||
proxmox::tools::fs::lock_file(&mut handle, exclusive, Some(std::time::Duration::from_nanos(0)))
|
|
||||||
.map_err(|err| {
|
|
||||||
format_err!(
|
|
||||||
"unable to acquire lock on {} directory {:?} - {}", what, path,
|
|
||||||
if err.would_block() {
|
|
||||||
String::from(would_block_msg)
|
|
||||||
} else {
|
|
||||||
err.to_string()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get an iterator over lines of a file, skipping empty lines and comments (lines starting with a
|
|
||||||
/// `#`).
|
|
||||||
pub fn file_get_non_comment_lines<P: AsRef<Path>>(
|
|
||||||
path: P,
|
|
||||||
) -> Result<impl Iterator<Item = io::Result<String>>, Error> {
|
|
||||||
let path = path.as_ref();
|
|
||||||
|
|
||||||
Ok(io::BufReader::new(
|
|
||||||
File::open(path).map_err(|err| format_err!("error opening {:?}: {}", path, err))?,
|
|
||||||
)
|
|
||||||
.lines()
|
|
||||||
.filter_map(|line| match line {
|
|
||||||
Ok(line) => {
|
|
||||||
let line = line.trim();
|
|
||||||
if line.is_empty() || line.starts_with('#') {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(Ok(line.to_string()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => Some(Err(err)),
|
|
||||||
}))
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! I/O utilities.
|
//! I/O utilities.
|
||||||
|
|
||||||
use proxmox::tools::fd::Fd;
|
use proxmox_sys::fd::Fd;
|
||||||
|
|
||||||
/// The `BufferedRead` trait provides a single function
|
/// The `BufferedRead` trait provides a single function
|
||||||
/// `buffered_read`. It returns a reference to an internal buffer. The
|
/// `buffered_read`. It returns a reference to an internal buffer. The
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
pub mod acl;
|
|
||||||
pub mod cert;
|
pub mod cert;
|
||||||
pub mod cli;
|
pub mod cli;
|
||||||
pub mod crypt_config;
|
pub mod crypt_config;
|
||||||
pub mod format;
|
pub mod format;
|
||||||
pub mod fs;
|
|
||||||
pub mod io;
|
pub mod io;
|
||||||
pub mod json;
|
pub mod json;
|
||||||
pub mod lru_cache;
|
pub mod lru_cache;
|
||||||
|
@ -14,9 +12,5 @@ pub mod str;
|
||||||
pub mod sync;
|
pub mod sync;
|
||||||
pub mod sys;
|
pub mod sys;
|
||||||
pub mod ticket;
|
pub mod ticket;
|
||||||
pub mod xattr;
|
|
||||||
|
|
||||||
pub mod async_lru_cache;
|
pub mod async_lru_cache;
|
||||||
|
|
||||||
mod command;
|
|
||||||
pub use command::{command_output, command_output_as_string, run_command};
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ impl Write for StdChannelWriter {
|
||||||
fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
|
fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
|
||||||
self.0
|
self.0
|
||||||
.send(Ok(buf.to_vec()))
|
.send(Ok(buf.to_vec()))
|
||||||
.map_err(proxmox::sys::error::io_err_other)
|
.map_err(proxmox_sys::error::io_err_other)
|
||||||
.and(Ok(buf.len()))
|
.and(Ok(buf.len()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,230 +0,0 @@
|
||||||
//! Wrapper functions for the libc xattr calls
|
|
||||||
|
|
||||||
use std::ffi::CStr;
|
|
||||||
use std::os::unix::io::RawFd;
|
|
||||||
|
|
||||||
use nix::errno::Errno;
|
|
||||||
|
|
||||||
use proxmox_io::vec;
|
|
||||||
use proxmox_lang::c_str;
|
|
||||||
|
|
||||||
/// `"security.capability"` as a CStr to avoid typos.
|
|
||||||
///
|
|
||||||
/// This cannot be `const` until `const_cstr_unchecked` is stable.
|
|
||||||
#[inline]
|
|
||||||
pub fn xattr_name_fcaps() -> &'static CStr {
|
|
||||||
c_str!("security.capability")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `"system.posix_acl_access"` as a CStr to avoid typos.
|
|
||||||
///
|
|
||||||
/// This cannot be `const` until `const_cstr_unchecked` is stable.
|
|
||||||
#[inline]
|
|
||||||
pub fn xattr_acl_access() -> &'static CStr {
|
|
||||||
c_str!("system.posix_acl_access")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `"system.posix_acl_default"` as a CStr to avoid typos.
|
|
||||||
///
|
|
||||||
/// This cannot be `const` until `const_cstr_unchecked` is stable.
|
|
||||||
#[inline]
|
|
||||||
pub fn xattr_acl_default() -> &'static CStr {
|
|
||||||
c_str!("system.posix_acl_default")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Result of `flistxattr`, allows iterating over the attributes as a list of `&CStr`s.
|
|
||||||
///
|
|
||||||
/// Listing xattrs produces a list separated by zeroes, inherently making them available as `&CStr`
|
|
||||||
/// already, so we make use of this fact and reflect this in the interface.
|
|
||||||
pub struct ListXAttr {
|
|
||||||
data: Vec<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ListXAttr {
|
|
||||||
fn new(data: Vec<u8>) -> Self {
|
|
||||||
Self { data }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> IntoIterator for &'a ListXAttr {
|
|
||||||
type Item = &'a CStr;
|
|
||||||
type IntoIter = ListXAttrIter<'a>;
|
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
|
||||||
ListXAttrIter {
|
|
||||||
data: &self.data,
|
|
||||||
at: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Iterator over the extended attribute entries in a `ListXAttr`.
|
|
||||||
pub struct ListXAttrIter<'a> {
|
|
||||||
data: &'a [u8],
|
|
||||||
at: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for ListXAttrIter<'a> {
|
|
||||||
type Item = &'a CStr;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<&'a CStr> {
|
|
||||||
let data = &self.data[self.at..];
|
|
||||||
let next = data.iter().position(|b| *b == 0)? + 1;
|
|
||||||
self.at += next;
|
|
||||||
Some(unsafe { CStr::from_bytes_with_nul_unchecked(&data[..next]) })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return a list of extended attributes accessible as an iterator over items of type `&CStr`.
|
|
||||||
pub fn flistxattr(fd: RawFd) -> Result<ListXAttr, nix::errno::Errno> {
|
|
||||||
// Initial buffer size for the attribute list, if content does not fit
|
|
||||||
// it gets dynamically increased until big enough.
|
|
||||||
let mut size = 256;
|
|
||||||
let mut buffer = vec::undefined(size);
|
|
||||||
let mut bytes = unsafe {
|
|
||||||
libc::flistxattr(fd, buffer.as_mut_ptr() as *mut libc::c_char, buffer.len())
|
|
||||||
};
|
|
||||||
while bytes < 0 {
|
|
||||||
let err = Errno::last();
|
|
||||||
match err {
|
|
||||||
Errno::ERANGE => {
|
|
||||||
// Buffer was not big enough to fit the list, retry with double the size
|
|
||||||
size = size.checked_mul(2).ok_or(Errno::ENOMEM)?;
|
|
||||||
},
|
|
||||||
_ => return Err(err),
|
|
||||||
}
|
|
||||||
// Retry to read the list with new buffer
|
|
||||||
buffer.resize(size, 0);
|
|
||||||
bytes = unsafe {
|
|
||||||
libc::flistxattr(fd, buffer.as_mut_ptr() as *mut libc::c_char, buffer.len())
|
|
||||||
};
|
|
||||||
}
|
|
||||||
buffer.truncate(bytes as usize);
|
|
||||||
|
|
||||||
Ok(ListXAttr::new(buffer))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get an extended attribute by name.
|
|
||||||
///
|
|
||||||
/// Extended attributes may not contain zeroes, which we enforce in the API by using a `&CStr`
|
|
||||||
/// type.
|
|
||||||
pub fn fgetxattr(fd: RawFd, name: &CStr) -> Result<Vec<u8>, nix::errno::Errno> {
|
|
||||||
let mut size = 256;
|
|
||||||
let mut buffer = vec::undefined(size);
|
|
||||||
let mut bytes = unsafe {
|
|
||||||
libc::fgetxattr(fd, name.as_ptr(), buffer.as_mut_ptr() as *mut core::ffi::c_void, buffer.len())
|
|
||||||
};
|
|
||||||
while bytes < 0 {
|
|
||||||
let err = Errno::last();
|
|
||||||
match err {
|
|
||||||
Errno::ERANGE => {
|
|
||||||
// Buffer was not big enough to fit the value, retry with double the size
|
|
||||||
size = size.checked_mul(2).ok_or(Errno::ENOMEM)?;
|
|
||||||
},
|
|
||||||
_ => return Err(err),
|
|
||||||
}
|
|
||||||
buffer.resize(size, 0);
|
|
||||||
bytes = unsafe {
|
|
||||||
libc::fgetxattr(fd, name.as_ptr() as *const libc::c_char, buffer.as_mut_ptr() as *mut core::ffi::c_void, buffer.len())
|
|
||||||
};
|
|
||||||
}
|
|
||||||
buffer.resize(bytes as usize, 0);
|
|
||||||
|
|
||||||
Ok(buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set an extended attribute on a file descriptor.
|
|
||||||
pub fn fsetxattr(fd: RawFd, name: &CStr, data: &[u8]) -> Result<(), nix::errno::Errno> {
|
|
||||||
let flags = 0 as libc::c_int;
|
|
||||||
let result = unsafe {
|
|
||||||
libc::fsetxattr(fd, name.as_ptr(), data.as_ptr() as *const libc::c_void, data.len(), flags)
|
|
||||||
};
|
|
||||||
if result < 0 {
|
|
||||||
return Err(Errno::last());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fsetxattr_fcaps(fd: RawFd, fcaps: &[u8]) -> Result<(), nix::errno::Errno> {
|
|
||||||
// TODO casync checks and removes capabilities if they are set
|
|
||||||
fsetxattr(fd, xattr_name_fcaps(), fcaps)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_security_capability(name: &CStr) -> bool {
|
|
||||||
name.to_bytes() == xattr_name_fcaps().to_bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_acl(name: &CStr) -> bool {
|
|
||||||
name.to_bytes() == xattr_acl_access().to_bytes()
|
|
||||||
|| name.to_bytes() == xattr_acl_default().to_bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if the passed name buffer starts with a valid xattr namespace prefix
|
|
||||||
/// and is within the length limit of 255 bytes
|
|
||||||
pub fn is_valid_xattr_name(c_name: &CStr) -> bool {
|
|
||||||
let name = c_name.to_bytes();
|
|
||||||
if name.is_empty() || name.len() > 255 {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if name.starts_with(b"user.") || name.starts_with(b"trusted.") {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// samba saves windows ACLs there
|
|
||||||
if name == b"security.NTACL" {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
is_security_capability(c_name)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
use std::ffi::CString;
|
|
||||||
use std::fs::OpenOptions;
|
|
||||||
use std::os::unix::io::AsRawFd;
|
|
||||||
|
|
||||||
use nix::errno::Errno;
|
|
||||||
|
|
||||||
use proxmox_lang::c_str;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_fsetxattr_fgetxattr() {
|
|
||||||
let path = "./test-xattrs.txt";
|
|
||||||
let file = OpenOptions::new()
|
|
||||||
.write(true)
|
|
||||||
.create(true)
|
|
||||||
.open(&path)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let fd = file.as_raw_fd();
|
|
||||||
|
|
||||||
assert!(fsetxattr(fd, c_str!("user.attribute0"), b"value0").is_ok());
|
|
||||||
assert!(fsetxattr(fd, c_str!("user.empty"), b"").is_ok());
|
|
||||||
|
|
||||||
if nix::unistd::Uid::current() != nix::unistd::ROOT {
|
|
||||||
assert_eq!(fsetxattr(fd, c_str!("trusted.attribute0"), b"value0"), Err(Errno::EPERM));
|
|
||||||
}
|
|
||||||
|
|
||||||
let v0 = fgetxattr(fd, c_str!("user.attribute0")).unwrap();
|
|
||||||
let v1 = fgetxattr(fd, c_str!("user.empty")).unwrap();
|
|
||||||
|
|
||||||
assert_eq!(v0, b"value0".as_ref());
|
|
||||||
assert_eq!(v1, b"".as_ref());
|
|
||||||
assert_eq!(fgetxattr(fd, c_str!("user.attribute1")), Err(Errno::ENODATA));
|
|
||||||
|
|
||||||
std::fs::remove_file(&path).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_is_valid_xattr_name() {
|
|
||||||
let too_long = CString::new(vec![b'a'; 265]).unwrap();
|
|
||||||
|
|
||||||
assert!(!is_valid_xattr_name(&too_long));
|
|
||||||
assert!(!is_valid_xattr_name(c_str!("system.attr")));
|
|
||||||
assert!(is_valid_xattr_name(c_str!("user.attr")));
|
|
||||||
assert!(is_valid_xattr_name(c_str!("trusted.attr")));
|
|
||||||
assert!(is_valid_xattr_name(super::xattr_name_fcaps()));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -22,11 +22,12 @@ zstd = { version = "0.6", features = [ "bindgen" ] }
|
||||||
pathpatterns = "0.1.2"
|
pathpatterns = "0.1.2"
|
||||||
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
|
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
|
||||||
|
|
||||||
proxmox = { version = "0.15.3", features = [ "sortable-macro" ] }
|
proxmox-async = "0.3"
|
||||||
proxmox-async = "0.2"
|
|
||||||
proxmox-router = { version = "1.1", features = [ "cli" ] }
|
proxmox-router = { version = "1.1", features = [ "cli" ] }
|
||||||
proxmox-schema = { version = "1", features = [ "api-macro" ] }
|
proxmox-schema = { version = "1", features = [ "api-macro" ] }
|
||||||
proxmox-time = "1"
|
proxmox-time = "1"
|
||||||
|
proxmox-sys = { version = "0.2", features = [ "sortable-macro" ] }
|
||||||
|
|
||||||
|
|
||||||
pbs-api-types = { path = "../pbs-api-types" }
|
pbs-api-types = { path = "../pbs-api-types" }
|
||||||
pbs-buildcfg = { path = "../pbs-buildcfg" }
|
pbs-buildcfg = { path = "../pbs-buildcfg" }
|
||||||
|
|
|
@ -267,7 +267,7 @@ fn test_crypt_speed(
|
||||||
|
|
||||||
let crypt_config = CryptConfig::new(testkey)?;
|
let crypt_config = CryptConfig::new(testkey)?;
|
||||||
|
|
||||||
//let random_data = proxmox::sys::linux::random_data(1024*1024)?;
|
//let random_data = proxmox_sys::linux::random_data(1024*1024)?;
|
||||||
let mut random_data = vec![];
|
let mut random_data = vec![];
|
||||||
// generate pseudo random byte sequence
|
// generate pseudo random byte sequence
|
||||||
for i in 0..256*1024 {
|
for i in 0..256*1024 {
|
||||||
|
|
|
@ -4,8 +4,8 @@ use std::path::PathBuf;
|
||||||
use anyhow::{bail, format_err, Error};
|
use anyhow::{bail, format_err, Error};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use proxmox::sys::linux::tty;
|
use proxmox_sys::linux::tty;
|
||||||
use proxmox::tools::fs::{file_get_contents, replace_file, CreateOptions};
|
use proxmox_sys::fs::{file_get_contents, replace_file, CreateOptions};
|
||||||
use proxmox_router::cli::{
|
use proxmox_router::cli::{
|
||||||
complete_file_name, format_and_print_result_full, get_output_format,
|
complete_file_name, format_and_print_result_full, get_output_format,
|
||||||
CliCommand, CliCommandMap, ColumnConfig,
|
CliCommand, CliCommandMap, ColumnConfig,
|
||||||
|
@ -54,7 +54,7 @@ fn create(kdf: Option<Kdf>, path: Option<String>, hint: Option<String>) -> Resul
|
||||||
let kdf = kdf.unwrap_or_default();
|
let kdf = kdf.unwrap_or_default();
|
||||||
|
|
||||||
let mut key = [0u8; 32];
|
let mut key = [0u8; 32];
|
||||||
proxmox::sys::linux::fill_with_random_data(&mut key)?;
|
proxmox_sys::linux::fill_with_random_data(&mut key)?;
|
||||||
|
|
||||||
match kdf {
|
match kdf {
|
||||||
Kdf::None => {
|
Kdf::None => {
|
||||||
|
|
|
@ -13,7 +13,7 @@ use tokio_stream::wrappers::ReceiverStream;
|
||||||
use xdg::BaseDirectories;
|
use xdg::BaseDirectories;
|
||||||
|
|
||||||
use pathpatterns::{MatchEntry, MatchType, PatternFlag};
|
use pathpatterns::{MatchEntry, MatchType, PatternFlag};
|
||||||
use proxmox::tools::fs::{file_get_json, replace_file, CreateOptions, image_size};
|
use proxmox_sys::fs::{file_get_json, replace_file, CreateOptions, image_size};
|
||||||
use proxmox_router::{ApiMethod, RpcEnvironment, cli::*};
|
use proxmox_router::{ApiMethod, RpcEnvironment, cli::*};
|
||||||
use proxmox_schema::api;
|
use proxmox_schema::api;
|
||||||
use proxmox_time::{strftime_local, epoch_i64};
|
use proxmox_time::{strftime_local, epoch_i64};
|
||||||
|
@ -654,7 +654,7 @@ async fn create_backup(
|
||||||
|
|
||||||
let crypto = crypto_parameters(¶m)?;
|
let crypto = crypto_parameters(¶m)?;
|
||||||
|
|
||||||
let backup_id = param["backup-id"].as_str().unwrap_or(&proxmox::tools::nodename());
|
let backup_id = param["backup-id"].as_str().unwrap_or(&proxmox_sys::nodename());
|
||||||
|
|
||||||
let backup_type = param["backup-type"].as_str().unwrap_or("host");
|
let backup_type = param["backup-type"].as_str().unwrap_or("host");
|
||||||
|
|
||||||
|
@ -751,7 +751,7 @@ async fn create_backup(
|
||||||
|
|
||||||
println!("Starting backup: {}/{}/{}", backup_type, backup_id, BackupDir::backup_time_to_string(backup_time)?);
|
println!("Starting backup: {}/{}/{}", backup_type, backup_id, BackupDir::backup_time_to_string(backup_time)?);
|
||||||
|
|
||||||
println!("Client name: {}", proxmox::tools::nodename());
|
println!("Client name: {}", proxmox_sys::nodename());
|
||||||
|
|
||||||
let start_time = std::time::Instant::now();
|
let start_time = std::time::Instant::now();
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,8 @@ use nix::unistd::{fork, ForkResult};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use tokio::signal::unix::{signal, SignalKind};
|
use tokio::signal::unix::{signal, SignalKind};
|
||||||
|
|
||||||
use proxmox::{sortable, identity};
|
use proxmox_sys::{sortable, identity};
|
||||||
use proxmox::tools::fd::Fd;
|
use proxmox_sys::fd::Fd;
|
||||||
use proxmox_router::{ApiHandler, ApiMethod, RpcEnvironment, cli::*};
|
use proxmox_router::{ApiHandler, ApiMethod, RpcEnvironment, cli::*};
|
||||||
use proxmox_schema::*;
|
use proxmox_schema::*;
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ fn complete_mapping_names<S: BuildHasher>(_arg: &str, _param: &HashMap<String, S
|
||||||
match pbs_fuse_loop::find_all_mappings() {
|
match pbs_fuse_loop::find_all_mappings() {
|
||||||
Ok(mappings) => mappings
|
Ok(mappings) => mappings
|
||||||
.filter_map(|(name, _)| {
|
.filter_map(|(name, _)| {
|
||||||
proxmox::tools::systemd::unescape_unit(&name).ok()
|
proxmox_sys::systemd::unescape_unit(&name).ok()
|
||||||
}).collect(),
|
}).collect(),
|
||||||
Err(_) => Vec::new()
|
Err(_) => Vec::new()
|
||||||
}
|
}
|
||||||
|
@ -280,7 +280,7 @@ async fn mount_do(param: Value, pipe: Option<Fd>) -> Result<Value, Error> {
|
||||||
let reader = CachedChunkReader::new(chunk_reader, index, 8).seekable();
|
let reader = CachedChunkReader::new(chunk_reader, index, 8).seekable();
|
||||||
|
|
||||||
let name = &format!("{}:{}/{}", repo.to_string(), path, archive_name);
|
let name = &format!("{}:{}/{}", repo.to_string(), path, archive_name);
|
||||||
let name_escaped = proxmox::tools::systemd::escape_unit(name, false);
|
let name_escaped = proxmox_sys::systemd::escape_unit(name, false);
|
||||||
|
|
||||||
let mut session = pbs_fuse_loop::FuseLoopSession::map_loop(size, reader, &name_escaped, options).await?;
|
let mut session = pbs_fuse_loop::FuseLoopSession::map_loop(size, reader, &name_escaped, options).await?;
|
||||||
let loopdev = session.loopdev_path.clone();
|
let loopdev = session.loopdev_path.clone();
|
||||||
|
@ -342,7 +342,7 @@ fn unmap(
|
||||||
pbs_fuse_loop::cleanup_unused_run_files(None);
|
pbs_fuse_loop::cleanup_unused_run_files(None);
|
||||||
let mut any = false;
|
let mut any = false;
|
||||||
for (backing, loopdev) in pbs_fuse_loop::find_all_mappings()? {
|
for (backing, loopdev) in pbs_fuse_loop::find_all_mappings()? {
|
||||||
let name = proxmox::tools::systemd::unescape_unit(&backing)?;
|
let name = proxmox_sys::systemd::unescape_unit(&backing)?;
|
||||||
println!("{}:\t{}", loopdev.unwrap_or_else(|| "(unmapped)".to_string()), name);
|
println!("{}:\t{}", loopdev.unwrap_or_else(|| "(unmapped)".to_string()), name);
|
||||||
any = true;
|
any = true;
|
||||||
}
|
}
|
||||||
|
@ -361,7 +361,7 @@ fn unmap(
|
||||||
if name.starts_with("/dev/loop") {
|
if name.starts_with("/dev/loop") {
|
||||||
pbs_fuse_loop::unmap_loopdev(name)?;
|
pbs_fuse_loop::unmap_loopdev(name)?;
|
||||||
} else {
|
} else {
|
||||||
let name = proxmox::tools::systemd::escape_unit(&name, false);
|
let name = proxmox_sys::systemd::escape_unit(&name, false);
|
||||||
pbs_fuse_loop::unmap_name(name)?;
|
pbs_fuse_loop::unmap_name(name)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
use proxmox::tools::fs::file_get_contents;
|
use proxmox_sys::fs::file_get_contents;
|
||||||
use proxmox_router::cli::*;
|
use proxmox_router::cli::*;
|
||||||
use proxmox_schema::api;
|
use proxmox_schema::api;
|
||||||
|
|
||||||
|
|
|
@ -16,14 +16,14 @@ tokio = { version = "1.6", features = [ "io-std", "rt", "rt-multi-thread", "time
|
||||||
|
|
||||||
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
|
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
|
||||||
|
|
||||||
proxmox = { version = "0.15.3" }
|
#proxmox = { version = "0.15.3" }
|
||||||
proxmox-async = "0.2"
|
proxmox-async = "0.3"
|
||||||
proxmox-lang = "1"
|
proxmox-lang = "1"
|
||||||
proxmox-router = { version = "1.1", features = [ "cli" ] }
|
proxmox-router = { version = "1.1", features = [ "cli" ] }
|
||||||
proxmox-schema = { version = "1", features = [ "api-macro" ] }
|
proxmox-schema = { version = "1", features = [ "api-macro" ] }
|
||||||
proxmox-time = "1"
|
proxmox-time = "1"
|
||||||
proxmox-uuid = "1"
|
proxmox-uuid = "1"
|
||||||
proxmox-sys = "0.1.2"
|
proxmox-sys = "0.2"
|
||||||
|
|
||||||
pbs-api-types = { path = "../pbs-api-types" }
|
pbs-api-types = { path = "../pbs-api-types" }
|
||||||
pbs-buildcfg = { path = "../pbs-buildcfg" }
|
pbs-buildcfg = { path = "../pbs-buildcfg" }
|
||||||
|
|
|
@ -8,7 +8,7 @@ use futures::FutureExt;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
use proxmox::tools::fs::lock_file;
|
use proxmox_sys::fs::lock_file;
|
||||||
|
|
||||||
use pbs_client::{DEFAULT_VSOCK_PORT, BackupRepository, VsockClient};
|
use pbs_client::{DEFAULT_VSOCK_PORT, BackupRepository, VsockClient};
|
||||||
use pbs_datastore::backup_info::BackupDir;
|
use pbs_datastore::backup_info::BackupDir;
|
||||||
|
@ -80,7 +80,7 @@ impl VMStateMap {
|
||||||
|
|
||||||
fn make_name(repo: &BackupRepository, snap: &BackupDir) -> String {
|
fn make_name(repo: &BackupRepository, snap: &BackupDir) -> String {
|
||||||
let full = format!("qemu_{}/{}", repo, snap);
|
let full = format!("qemu_{}/{}", repo, snap);
|
||||||
proxmox::tools::systemd::escape_unit(&full, false)
|
proxmox_sys::systemd::escape_unit(&full, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// remove non-responsive VMs from given map, returns 'true' if map was modified
|
/// remove non-responsive VMs from given map, returns 'true' if map was modified
|
||||||
|
@ -257,7 +257,7 @@ impl BlockRestoreDriver for QemuBlockDriver {
|
||||||
let resp = client
|
let resp = client
|
||||||
.get("api2/json/status", Some(json!({"keep-timeout": true})))
|
.get("api2/json/status", Some(json!({"keep-timeout": true})))
|
||||||
.await;
|
.await;
|
||||||
let name = proxmox::tools::systemd::unescape_unit(n)
|
let name = proxmox_sys::systemd::unescape_unit(n)
|
||||||
.unwrap_or_else(|_| "<invalid name>".to_owned());
|
.unwrap_or_else(|_| "<invalid name>".to_owned());
|
||||||
let mut extra = json!({"pid": s.pid, "cid": s.cid});
|
let mut extra = json!({"pid": s.pid, "cid": s.cid});
|
||||||
|
|
||||||
|
@ -295,7 +295,7 @@ impl BlockRestoreDriver for QemuBlockDriver {
|
||||||
|
|
||||||
fn stop(&self, id: String) -> Async<Result<(), Error>> {
|
fn stop(&self, id: String) -> Async<Result<(), Error>> {
|
||||||
async move {
|
async move {
|
||||||
let name = proxmox::tools::systemd::escape_unit(&id, false);
|
let name = proxmox_sys::systemd::escape_unit(&id, false);
|
||||||
let mut map = VMStateMap::load()?;
|
let mut map = VMStateMap::load()?;
|
||||||
let map_mod = cleanup_map(&mut map.map).await;
|
let map_mod = cleanup_map(&mut map.map).await;
|
||||||
match map.map.get(&name) {
|
match map.map.get(&name) {
|
||||||
|
@ -325,7 +325,7 @@ impl BlockRestoreDriver for QemuBlockDriver {
|
||||||
match VMStateMap::load_read_only() {
|
match VMStateMap::load_read_only() {
|
||||||
Ok(state) => state
|
Ok(state) => state
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(name, _)| proxmox::tools::systemd::unescape_unit(&name).ok())
|
.filter_map(|(name, _)| proxmox_sys::systemd::unescape_unit(&name).ok())
|
||||||
.collect(),
|
.collect(),
|
||||||
Err(_) => Vec::new(),
|
Err(_) => Vec::new(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use std::sync::Arc;
|
||||||
use anyhow::{bail, format_err, Error};
|
use anyhow::{bail, format_err, Error};
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
use proxmox::tools::fs::{create_path, CreateOptions};
|
use proxmox_sys::fs::{create_path, CreateOptions};
|
||||||
use proxmox_router::cli::{
|
use proxmox_router::cli::{
|
||||||
complete_file_name, default_table_format_options,
|
complete_file_name, default_table_format_options,
|
||||||
format_and_print_result_full, get_output_format,
|
format_and_print_result_full, get_output_format,
|
||||||
|
|
|
@ -11,8 +11,8 @@ use tokio::time;
|
||||||
use nix::sys::signal::{kill, Signal};
|
use nix::sys::signal::{kill, Signal};
|
||||||
use nix::unistd::Pid;
|
use nix::unistd::Pid;
|
||||||
|
|
||||||
use proxmox::tools::fs::{create_path, file_read_string, make_tmp_file, CreateOptions};
|
use proxmox_sys::fs::{create_path, file_read_string, make_tmp_file, CreateOptions};
|
||||||
use proxmox::tools::fd::fd_change_cloexec;
|
use proxmox_sys::fd::fd_change_cloexec;
|
||||||
use proxmox_sys::logrotate::LogRotate;
|
use proxmox_sys::logrotate::LogRotate;
|
||||||
|
|
||||||
use pbs_client::{VsockClient, DEFAULT_VSOCK_PORT};
|
use pbs_client::{VsockClient, DEFAULT_VSOCK_PORT};
|
||||||
|
|
|
@ -30,12 +30,12 @@ tokio-openssl = "0.6.1"
|
||||||
tower-service = "0.3.0"
|
tower-service = "0.3.0"
|
||||||
url = "2.1"
|
url = "2.1"
|
||||||
|
|
||||||
proxmox = "0.15.3"
|
#proxmox = "0.15.3"
|
||||||
proxmox-async = "0.2"
|
proxmox-async = "0.3"
|
||||||
proxmox-io = "1"
|
proxmox-io = "1"
|
||||||
proxmox-lang = "1"
|
proxmox-lang = "1"
|
||||||
proxmox-http = { version = "0.5.0", features = [ "client" ] }
|
proxmox-http = { version = "0.6", features = [ "client" ] }
|
||||||
proxmox-router = "1.1"
|
proxmox-router = "1.1"
|
||||||
proxmox-schema = { version = "1", features = [ "api-macro", "upid-api-impl" ] }
|
proxmox-schema = { version = "1", features = [ "api-macro", "upid-api-impl" ] }
|
||||||
proxmox-time = "1"
|
proxmox-time = "1"
|
||||||
proxmox-sys = "0.1.2"
|
proxmox-sys = "0.2"
|
||||||
|
|
|
@ -12,7 +12,7 @@ use hyper::http::request::Parts;
|
||||||
use handlebars::Handlebars;
|
use handlebars::Handlebars;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use proxmox::tools::fs::{create_path, CreateOptions};
|
use proxmox_sys::fs::{create_path, CreateOptions};
|
||||||
use proxmox_router::{ApiMethod, Router, RpcEnvironmentType, UserInformation};
|
use proxmox_router::{ApiMethod, Router, RpcEnvironmentType, UserInformation};
|
||||||
|
|
||||||
use crate::{ServerAdapter, AuthError, FileLogger, FileLogOptions, CommandSocket, RestEnvironment};
|
use crate::{ServerAdapter, AuthError, FileLogger, FileLogOptions, CommandSocket, RestEnvironment};
|
||||||
|
|
|
@ -13,7 +13,7 @@ use anyhow::{bail, format_err, Error};
|
||||||
use futures::future::{self, Either};
|
use futures::future::{self, Either};
|
||||||
use nix::unistd::{fork, ForkResult};
|
use nix::unistd::{fork, ForkResult};
|
||||||
|
|
||||||
use proxmox::tools::fd::{fd_change_cloexec, Fd};
|
use proxmox_sys::fd::{fd_change_cloexec, Fd};
|
||||||
use proxmox_io::{ReadExt, WriteExt};
|
use proxmox_io::{ReadExt, WriteExt};
|
||||||
|
|
||||||
// Unfortunately FnBox is nightly-only and Box<FnOnce> is unusable, so just use Box<Fn>...
|
// Unfortunately FnBox is nightly-only and Box<FnOnce> is unusable, so just use Box<Fn>...
|
||||||
|
@ -129,14 +129,14 @@ impl Reloader {
|
||||||
let ident = ident.as_bytes();
|
let ident = ident.as_bytes();
|
||||||
let fd = unsafe { sd_journal_stream_fd(ident.as_ptr(), libc::LOG_INFO, 1) };
|
let fd = unsafe { sd_journal_stream_fd(ident.as_ptr(), libc::LOG_INFO, 1) };
|
||||||
if fd >= 0 && fd != 1 {
|
if fd >= 0 && fd != 1 {
|
||||||
let fd = proxmox::tools::fd::Fd(fd); // add drop handler
|
let fd = proxmox_sys::fd::Fd(fd); // add drop handler
|
||||||
nix::unistd::dup2(fd.as_raw_fd(), 1)?;
|
nix::unistd::dup2(fd.as_raw_fd(), 1)?;
|
||||||
} else {
|
} else {
|
||||||
log::error!("failed to update STDOUT journal redirection ({})", fd);
|
log::error!("failed to update STDOUT journal redirection ({})", fd);
|
||||||
}
|
}
|
||||||
let fd = unsafe { sd_journal_stream_fd(ident.as_ptr(), libc::LOG_ERR, 1) };
|
let fd = unsafe { sd_journal_stream_fd(ident.as_ptr(), libc::LOG_ERR, 1) };
|
||||||
if fd >= 0 && fd != 2 {
|
if fd >= 0 && fd != 2 {
|
||||||
let fd = proxmox::tools::fd::Fd(fd); // add drop handler
|
let fd = proxmox_sys::fd::Fd(fd); // add drop handler
|
||||||
nix::unistd::dup2(fd.as_raw_fd(), 2)?;
|
nix::unistd::dup2(fd.as_raw_fd(), 2)?;
|
||||||
} else {
|
} else {
|
||||||
log::error!("failed to update STDERR journal redirection ({})", fd);
|
log::error!("failed to update STDERR journal redirection ({})", fd);
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::io::Write;
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
use nix::fcntl::OFlag;
|
use nix::fcntl::OFlag;
|
||||||
|
|
||||||
use proxmox::tools::fs::{CreateOptions, atomic_open_or_create_file};
|
use proxmox_sys::fs::{CreateOptions, atomic_open_or_create_file};
|
||||||
|
|
||||||
/// Options to control the behavior of a [FileLogger] instance
|
/// Options to control the behavior of a [FileLogger] instance
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
|
@ -25,9 +25,9 @@ use hyper::{Body, Response, Method};
|
||||||
use http::request::Parts;
|
use http::request::Parts;
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
|
|
||||||
use proxmox::tools::fd::Fd;
|
use proxmox_sys::fd::Fd;
|
||||||
use proxmox::sys::linux::procfs::PidStat;
|
use proxmox_sys::linux::procfs::PidStat;
|
||||||
use proxmox::tools::fs::CreateOptions;
|
use proxmox_sys::fs::CreateOptions;
|
||||||
use proxmox_router::UserInformation;
|
use proxmox_router::UserInformation;
|
||||||
|
|
||||||
mod compression;
|
mod compression;
|
||||||
|
@ -117,12 +117,12 @@ pub(crate) fn pstart() -> u64 {
|
||||||
/// Helper to write the PID into a file
|
/// Helper to write the PID into a file
|
||||||
pub fn write_pid(pid_fn: &str) -> Result<(), Error> {
|
pub fn write_pid(pid_fn: &str) -> Result<(), Error> {
|
||||||
let pid_str = format!("{}\n", *PID);
|
let pid_str = format!("{}\n", *PID);
|
||||||
proxmox::tools::fs::replace_file(pid_fn, pid_str.as_bytes(), CreateOptions::new(), false)
|
proxmox_sys::fs::replace_file(pid_fn, pid_str.as_bytes(), CreateOptions::new(), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper to read the PID from a file
|
/// Helper to read the PID from a file
|
||||||
pub fn read_pid(pid_fn: &str) -> Result<i32, Error> {
|
pub fn read_pid(pid_fn: &str) -> Result<i32, Error> {
|
||||||
let pid = proxmox::tools::fs::file_get_contents(pid_fn)?;
|
let pid = proxmox_sys::fs::file_get_contents(pid_fn)?;
|
||||||
let pid = std::str::from_utf8(&pid)?.trim();
|
let pid = std::str::from_utf8(&pid)?.trim();
|
||||||
pid.parse().map_err(|err| format_err!("could not parse pid - {}", err))
|
pid.parse().map_err(|err| format_err!("could not parse pid - {}", err))
|
||||||
}
|
}
|
||||||
|
|
|
@ -479,7 +479,7 @@ pub(crate) async fn handle_api_request<Env: RpcEnvironment, S: 'static + BuildHa
|
||||||
resp.map(|body| {
|
resp.map(|body| {
|
||||||
Body::wrap_stream(DeflateEncoder::with_quality(
|
Body::wrap_stream(DeflateEncoder::with_quality(
|
||||||
TryStreamExt::map_err(body, |err| {
|
TryStreamExt::map_err(body, |err| {
|
||||||
proxmox::io_format_err!("error during compression: {}", err)
|
proxmox_sys::io_format_err!("error during compression: {}", err)
|
||||||
}),
|
}),
|
||||||
Level::Default,
|
Level::Default,
|
||||||
))
|
))
|
||||||
|
|
|
@ -16,12 +16,12 @@ use tokio::sync::oneshot;
|
||||||
use nix::fcntl::OFlag;
|
use nix::fcntl::OFlag;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
|
|
||||||
use proxmox::sys::linux::procfs;
|
use proxmox_sys::linux::procfs;
|
||||||
use proxmox::tools::fs::{create_path, replace_file, atomic_open_or_create_file, CreateOptions};
|
use proxmox_sys::fs::{create_path, replace_file, atomic_open_or_create_file, CreateOptions};
|
||||||
use proxmox_lang::try_block;
|
use proxmox_lang::try_block;
|
||||||
use proxmox_schema::upid::UPID;
|
use proxmox_schema::upid::UPID;
|
||||||
|
|
||||||
use proxmox_sys::worker_task_context::{WorkerTaskContext};
|
use proxmox_sys::WorkerTaskContext;
|
||||||
use proxmox_sys::logrotate::{LogRotate, LogRotateFiles};
|
use proxmox_sys::logrotate::{LogRotate, LogRotateFiles};
|
||||||
|
|
||||||
use crate::{CommandSocket, FileLogger, FileLogOptions};
|
use crate::{CommandSocket, FileLogger, FileLogOptions};
|
||||||
|
@ -79,7 +79,7 @@ impl WorkerTaskSetup {
|
||||||
|
|
||||||
let timeout = std::time::Duration::new(10, 0);
|
let timeout = std::time::Duration::new(10, 0);
|
||||||
|
|
||||||
let file = proxmox::tools::fs::open_file_locked(
|
let file = proxmox_sys::fs::open_file_locked(
|
||||||
&self.task_lock_fn,
|
&self.task_lock_fn,
|
||||||
timeout,
|
timeout,
|
||||||
exclusive,
|
exclusive,
|
||||||
|
|
|
@ -26,11 +26,11 @@ tokio-util = { version = "0.6", features = [ "codec", "io" ] }
|
||||||
pathpatterns = "0.1.2"
|
pathpatterns = "0.1.2"
|
||||||
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
|
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
|
||||||
|
|
||||||
proxmox = { version = "0.15.3", features = [ "sortable-macro" ] }
|
proxmox-async = "0.3"
|
||||||
proxmox-async = "0.2"
|
|
||||||
proxmox-router = { version = "1.1", features = [ "cli" ] }
|
proxmox-router = { version = "1.1", features = [ "cli" ] }
|
||||||
proxmox-schema = { version = "1", features = [ "api-macro" ] }
|
proxmox-schema = { version = "1", features = [ "api-macro" ] }
|
||||||
proxmox-time = "1"
|
proxmox-time = "1"
|
||||||
|
proxmox-sys = { version = "0.2", features = [ "sortable-macro" ] }
|
||||||
|
|
||||||
pbs-api-types = { path = "../pbs-api-types" }
|
pbs-api-types = { path = "../pbs-api-types" }
|
||||||
pbs-tools = { path = "../pbs-tools" }
|
pbs-tools = { path = "../pbs-tools" }
|
||||||
|
|
|
@ -13,18 +13,18 @@ use serde_json::Value;
|
||||||
use tokio::sync::Semaphore;
|
use tokio::sync::Semaphore;
|
||||||
|
|
||||||
use pathpatterns::{MatchEntry, MatchPattern, MatchType, Pattern};
|
use pathpatterns::{MatchEntry, MatchPattern, MatchType, Pattern};
|
||||||
use proxmox::{identity, sortable};
|
|
||||||
use proxmox_router::{
|
use proxmox_router::{
|
||||||
list_subdirs_api_method,
|
list_subdirs_api_method,
|
||||||
ApiHandler, ApiMethod, ApiResponseFuture, Permission, Router, RpcEnvironment, SubdirMap,
|
ApiHandler, ApiMethod, ApiResponseFuture, Permission, Router, RpcEnvironment, SubdirMap,
|
||||||
};
|
};
|
||||||
use proxmox_schema::*;
|
use proxmox_schema::*;
|
||||||
use proxmox_async::zip::zip_directory;
|
use proxmox_async::zip::zip_directory;
|
||||||
|
use proxmox_sys::fs::read_subdir;
|
||||||
|
use proxmox_sys::{identity, sortable};
|
||||||
|
|
||||||
use pbs_api_types::file_restore::RestoreDaemonStatus;
|
use pbs_api_types::file_restore::RestoreDaemonStatus;
|
||||||
use pbs_client::pxar::{create_archive, Flags, PxarCreateOptions, ENCODER_MAX_ENTRIES};
|
use pbs_client::pxar::{create_archive, Flags, PxarCreateOptions, ENCODER_MAX_ENTRIES};
|
||||||
use pbs_datastore::catalog::{ArchiveEntry, DirEntryAttribute};
|
use pbs_datastore::catalog::{ArchiveEntry, DirEntryAttribute};
|
||||||
use pbs_tools::fs::read_subdir;
|
|
||||||
use pbs_tools::json::required_string_param;
|
use pbs_tools::json::required_string_param;
|
||||||
|
|
||||||
use pxar::encoder::aio::TokioWriter;
|
use pxar::encoder::aio::TokioWriter;
|
||||||
|
|
|
@ -9,11 +9,11 @@ use anyhow::{bail, format_err, Error};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
|
||||||
use proxmox::tools::fs;
|
use proxmox_sys::fs;
|
||||||
|
use proxmox_sys::command::run_command;
|
||||||
use proxmox_schema::const_regex;
|
use proxmox_schema::const_regex;
|
||||||
|
|
||||||
use pbs_api_types::BLOCKDEVICE_NAME_REGEX;
|
use pbs_api_types::BLOCKDEVICE_NAME_REGEX;
|
||||||
use pbs_tools::run_command;
|
|
||||||
|
|
||||||
const_regex! {
|
const_regex! {
|
||||||
VIRTIO_PART_REGEX = r"^vd[a-z]+(\d+)$";
|
VIRTIO_PART_REGEX = r"^vd[a-z]+(\d+)$";
|
||||||
|
@ -371,7 +371,7 @@ impl DiskState {
|
||||||
|
|
||||||
// create mapping for virtio drives and .fidx files (via serial description)
|
// create mapping for virtio drives and .fidx files (via serial description)
|
||||||
// note: disks::DiskManager relies on udev, which we don't have
|
// note: disks::DiskManager relies on udev, which we don't have
|
||||||
for entry in pbs_tools::fs::scan_subdir(
|
for entry in proxmox_sys::fs::scan_subdir(
|
||||||
libc::AT_FDCWD,
|
libc::AT_FDCWD,
|
||||||
"/sys/block",
|
"/sys/block",
|
||||||
&BLOCKDEVICE_NAME_REGEX,
|
&BLOCKDEVICE_NAME_REGEX,
|
||||||
|
@ -416,7 +416,7 @@ impl DiskState {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut parts = Vec::new();
|
let mut parts = Vec::new();
|
||||||
for entry in pbs_tools::fs::scan_subdir(
|
for entry in proxmox_sys::fs::scan_subdir(
|
||||||
libc::AT_FDCWD,
|
libc::AT_FDCWD,
|
||||||
sys_path,
|
sys_path,
|
||||||
&VIRTIO_PART_REGEX,
|
&VIRTIO_PART_REGEX,
|
||||||
|
|
|
@ -19,6 +19,7 @@ serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde_cbor = "0.11.1"
|
serde_cbor = "0.11.1"
|
||||||
|
|
||||||
proxmox = { version = "0.15.3" }
|
#proxmox = { version = "0.15.3" }
|
||||||
proxmox-time = "1"
|
proxmox-time = "1"
|
||||||
proxmox-schema = { version = "1", features = [ "api-macro" ] }
|
proxmox-schema = { version = "1", features = [ "api-macro" ] }
|
||||||
|
proxmox-sys = "0.2"
|
|
@ -11,7 +11,7 @@ use proxmox_router::cli::{run_cli_command, complete_file_name, CliCommand, CliCo
|
||||||
use proxmox_schema::{api, parse_property_string};
|
use proxmox_schema::{api, parse_property_string};
|
||||||
use proxmox_schema::{ApiStringFormat, ApiType, IntegerSchema, Schema, StringSchema};
|
use proxmox_schema::{ApiStringFormat, ApiType, IntegerSchema, Schema, StringSchema};
|
||||||
|
|
||||||
use proxmox::tools::fs::CreateOptions;
|
use proxmox_sys::fs::CreateOptions;
|
||||||
|
|
||||||
use proxmox_rrd::rrd::{CF, DST, RRA, RRD};
|
use proxmox_rrd::rrd::{CF, DST, RRA, RRD};
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ use std::collections::BTreeSet;
|
||||||
use crossbeam_channel::{bounded, TryRecvError};
|
use crossbeam_channel::{bounded, TryRecvError};
|
||||||
use anyhow::{format_err, bail, Error};
|
use anyhow::{format_err, bail, Error};
|
||||||
|
|
||||||
use proxmox::tools::fs::{create_path, CreateOptions};
|
use proxmox_sys::fs::{create_path, CreateOptions};
|
||||||
|
|
||||||
use crate::rrd::{DST, CF, RRD, RRA};
|
use crate::rrd::{DST, CF, RRD, RRA};
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ use anyhow::{bail, format_err, Error};
|
||||||
use nix::fcntl::OFlag;
|
use nix::fcntl::OFlag;
|
||||||
use crossbeam_channel::Receiver;
|
use crossbeam_channel::Receiver;
|
||||||
|
|
||||||
use proxmox::tools::fs::atomic_open_or_create_file;
|
use proxmox_sys::fs::atomic_open_or_create_file;
|
||||||
|
|
||||||
const RRD_JOURNAL_NAME: &str = "rrd.journal";
|
const RRD_JOURNAL_NAME: &str = "rrd.journal";
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue