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:
Dietmar Maurer 2021-11-23 17:57:00 +01:00
parent bd00ff10e4
commit 25877d05ac
201 changed files with 627 additions and 1535 deletions

View File

@ -94,8 +94,7 @@ zstd = { version = "0.6", features = [ "bindgen" ] }
pathpatterns = "0.1.2"
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
proxmox = { version = "0.15.3", features = [ "sortable-macro" ] }
proxmox-http = { version = "0.5.4", features = [ "client", "http-helpers", "websocket" ] }
proxmox-http = { version = "0.6", features = [ "client", "http-helpers", "websocket" ] }
proxmox-io = "1"
proxmox-lang = "1"
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-time = "1"
proxmox-uuid = "1"
proxmox-shared-memory = "0.1.1"
proxmox-sys = "0.1.2"
proxmox-serde = "0.1"
proxmox-shared-memory = "0.2"
proxmox-sys = { version = "0.2", features = [ "sortable-macro" ] }
proxmox-acme-rs = "0.3"
proxmox-apt = "0.8.0"
proxmox-async = "0.2"
proxmox-async = "0.3"
proxmox-openid = "0.9.0"
pbs-api-types = { path = "pbs-api-types" }

18
debian/control vendored
View File

@ -40,18 +40,15 @@ Build-Depends: debhelper (>= 12),
librust-pathpatterns-0.1+default-dev (>= 0.1.2-~~),
librust-percent-encoding-2+default-dev (>= 2.1-~~),
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-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-fuse-0.1+default-dev (>= 0.1.1-~~),
librust-proxmox-http-0.5+client-dev (>= 0.5.4-~~),
librust-proxmox-http-0.5+default-dev (>= 0.5.4-~~),
librust-proxmox-http-0.5+http-helpers-dev (>= 0.5.4-~~),
librust-proxmox-http-0.5+websocket-dev (>= 0.5.4-~~),
librust-proxmox-http-0.6+client-dev,
librust-proxmox-http-0.6+default-dev,
librust-proxmox-http-0.6+http-helpers-dev,
librust-proxmox-http-0.6+websocket-dev,
librust-proxmox-io-1+default-dev,
librust-proxmox-io-1+tokio-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+upid-api-impl-dev (>= 1.0.1-~~),
librust-proxmox-section-config-1+default-dev,
librust-proxmox-shared-memory-0.1+default-dev (>= 0.1.1-~~),
librust-proxmox-sys-0.1+default-dev (>= 0.1.2-~~),
librust-proxmox-shared-memory-0.2+default-dev,
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-types-dev (>= 1.3-~~),
librust-proxmox-tfa-1+default-dev (>= 1.3-~~),

View File

@ -27,7 +27,7 @@ fn rate_test(name: &str, bench: &dyn Fn() -> usize) {
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", &|| {
let mut crchasher = crc32fast::Hasher::new();
@ -46,9 +46,9 @@ fn main() -> Result<(), Error> {
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();

View File

@ -15,8 +15,10 @@ openssl = "0.10"
regex = "1.2"
serde = { version = "1.0", features = ["derive"] }
proxmox = "0.15.3"
proxmox-lang = "1.0.0"
proxmox-schema = { version = "1.0.1", features = [ "api-macro" ] }
proxmox-serde = "0.1"
proxmox-time = "1.1"
proxmox-uuid = { version = "1.0.0", features = [ "serde" ] }
proxmox-sys = "0.2" # only needed foör nodename()??

View File

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

View File

@ -51,7 +51,8 @@ impl std::str::FromStr for Fingerprint {
fn from_str(s: &str) -> Result<Self, Error> {
let mut tmp = s.to_string();
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))
}
}

View File

@ -216,8 +216,8 @@ impl std::str::FromStr for HumanByte {
}
}
proxmox::forward_deserialize_to_from_str!(HumanByte);
proxmox::forward_serialize_to_display!(HumanByte);
proxmox_serde::forward_deserialize_to_from_str!(HumanByte);
proxmox_serde::forward_serialize_to_display!(HumanByte);
#[test]
fn test_human_byte_parser() -> Result<(), Error> {

View File

@ -365,8 +365,8 @@ impl std::fmt::Display for GroupFilter {
}
}
proxmox::forward_deserialize_to_from_str!(GroupFilter);
proxmox::forward_serialize_to_display!(GroupFilter);
proxmox_serde::forward_deserialize_to_from_str!(GroupFilter);
proxmox_serde::forward_serialize_to_display!(GroupFilter);
fn verify_group_filter(input: &str) -> Result<(), anyhow::Error> {
GroupFilter::from_str(input).map(|_| ())

View File

@ -3,10 +3,11 @@
use serde::{Deserialize, Serialize};
use anyhow::bail;
pub mod common_regex;
use proxmox_schema::{
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;
#[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')")
.format(&ApiStringFormat::VerifyFn(|node| {
if node == "localhost" || node == proxmox::tools::nodename() {
if node == "localhost" || node == proxmox_sys::nodename() {
Ok(())
} else {
bail!("no such node '{}'", node);

View File

@ -79,7 +79,7 @@ pub struct Remote {
pub name: String,
// Note: The stored password is base64 encoded
#[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,
#[serde(flatten)]
pub config: RemoteConfig,

View File

@ -22,8 +22,8 @@ pub enum MediaLocation {
Vault(String),
}
proxmox::forward_deserialize_to_from_str!(MediaLocation);
proxmox::forward_serialize_to_display!(MediaLocation);
proxmox_serde::forward_deserialize_to_from_str!(MediaLocation);
proxmox_serde::forward_serialize_to_display!(MediaLocation);
impl proxmox_schema::ApiType for MediaLocation {
const API_SCHEMA: Schema = StringSchema::new(

View File

@ -685,8 +685,8 @@ fn test_token_id() {
assert_eq!(auth_id.to_string(), "test@pam!bar".to_string());
}
proxmox::forward_deserialize_to_from_str!(Userid);
proxmox::forward_serialize_to_display!(Userid);
proxmox_serde::forward_deserialize_to_from_str!(Userid);
proxmox_serde::forward_serialize_to_display!(Userid);
proxmox::forward_deserialize_to_from_str!(Authid);
proxmox::forward_serialize_to_display!(Authid);
proxmox_serde::forward_deserialize_to_from_str!(Authid);
proxmox_serde::forward_serialize_to_display!(Authid);

View File

@ -10,6 +10,7 @@ anyhow = "1.0"
bitflags = "1.2.1"
bytes = "1.0"
futures = "0.3"
hex = "0.4.3"
h2 = { version = "0.3", features = [ "stream" ] }
http = "0.2"
hyper = { version = "0.14", features = [ "full" ] }
@ -28,15 +29,17 @@ tower-service = "0.3.0"
xdg = "2.2"
pathpatterns = "0.1.2"
proxmox = "0.15.3"
proxmox-async = "0.2"
proxmox-async = "0.3"
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-lang = "1"
proxmox-router = { version = "1.1", features = [ "cli" ] }
proxmox-schema = "1"
proxmox-time = "1"
proxmox-sys = "0.2"
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
pbs-api-types = { path = "../pbs-api-types" }

View File

@ -7,8 +7,6 @@ use std::os::unix::fs::OpenOptionsExt;
use futures::future::AbortHandle;
use serde_json::{json, Value};
use proxmox::tools::digest_to_hex;
use pbs_tools::crypt_config::CryptConfig;
use pbs_tools::sha::sha256;
use pbs_datastore::{PROXMOX_BACKUP_READER_PROTOCOL_ID_V1, BackupManifest};
@ -121,7 +119,7 @@ impl BackupReader {
output: W,
) -> Result<(), Error> {
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
}

View File

@ -12,8 +12,6 @@ use tokio::io::AsyncReadExt;
use tokio::sync::{mpsc, oneshot};
use tokio_stream::wrappers::ReceiverStream;
use proxmox::tools::digest_to_hex;
use pbs_api_types::HumanByte;
use pbs_tools::crypt_config::CryptConfig;
use pbs_datastore::{CATALOG_NAME, PROXMOX_BACKUP_PROTOCOL_ID_V1};
@ -389,7 +387,7 @@ impl BackupWriter {
"wid": wid ,
"chunk-count": upload_stats.chunk_count,
"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?;
Ok(BackupStats {
@ -481,7 +479,7 @@ impl BackupWriter {
let mut digest_list = vec![];
let mut offset_list = vec![];
for (offset, digest) in chunk_list {
digest_list.push(digest_to_hex(&digest));
digest_list.push(hex::encode(&digest));
offset_list.push(offset);
}
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 {
let offset = chunk_info.offset;
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
if verbose {

View File

@ -14,7 +14,7 @@ use nix::fcntl::OFlag;
use nix::sys::stat::Mode;
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_schema::api;
use pxar::{EntryKind, Metadata};

View File

@ -14,10 +14,8 @@ use serde_json::{json, Value};
use percent_encoding::percent_encode;
use xdg::BaseDirectories;
use proxmox::{
sys::linux::tty,
tools::fs::{file_get_json, replace_file, CreateOptions},
};
use proxmox_sys::linux::tty;
use proxmox_sys::fs::{file_get_json, replace_file, CreateOptions};
use proxmox_router::HttpError;
use proxmox_http::client::{HttpsConnector, RateLimiter};
@ -521,7 +519,7 @@ impl HttpClient {
Ok(fp) => fp,
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())
.collect::<Vec<&str>>().join(":");

View File

@ -19,14 +19,14 @@ use pathpatterns::{MatchEntry, MatchFlag, MatchList, MatchType, PatternFlag};
use pxar::Metadata;
use pxar::encoder::{SeqWrite, LinkOffset};
use proxmox::sys::error::SysError;
use proxmox::tools::fd::RawFdNum;
use proxmox::tools::fd::Fd;
use proxmox_sys::error::SysError;
use proxmox_sys::fd::RawFdNum;
use proxmox_sys::fd::Fd;
use proxmox_sys::fs::{self, acl, xattr};
use proxmox_io::vec;
use proxmox_lang::c_str;
use pbs_datastore::catalog::BackupCatalogWriter;
use pbs_tools::{acl, fs, xattr};
use pbs_tools::str::strip_ascii_whitespace;
use crate::pxar::metadata::errno_is_unsupported;
@ -60,7 +60,7 @@ fn detect_fs_type(fd: RawFd) -> Result<i64, Error> {
#[rustfmt::skip]
pub fn is_virtual_file_system(magic: i64) -> bool {
use proxmox::sys::linux::magic::*;
use proxmox_sys::linux::magic::*;
matches!(magic, BINFMTFS_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> {
use proxmox::sys::linux::magic::*;
use proxmox_sys::linux::magic::*;
if fs_magic != MSDOS_SUPER_MAGIC && fs_magic != FUSE_SUPER_MAGIC {
return Ok(());
@ -891,7 +891,7 @@ fn get_quota_project_id(
return Ok(());
}
use proxmox::sys::linux::magic::*;
use proxmox_sys::linux::magic::*;
match magic {
EXT4_SUPER_MAGIC | XFS_SUPER_MAGIC | FUSE_SUPER_MAGIC | ZFS_SUPER_MAGIC => (),

View File

@ -7,8 +7,8 @@ use nix::dir::Dir;
use nix::fcntl::OFlag;
use nix::sys::stat::{mkdirat, Mode};
use proxmox::sys::error::SysError;
use proxmox::tools::fd::BorrowedFd;
use proxmox_sys::error::SysError;
use proxmox_sys::fd::BorrowedFd;
use pxar::Metadata;
use crate::pxar::tools::{assert_single_path_component, perms_from_metadata};

View File

@ -21,8 +21,8 @@ use pxar::decoder::aio::Decoder;
use pxar::format::Device;
use pxar::{Entry, EntryKind, Metadata};
use proxmox::c_result;
use proxmox::tools::fs::{create_path, CreateOptions};
use proxmox_sys::c_result;
use proxmox_sys::fs::{create_path, CreateOptions};
use proxmox_io::{sparse_copy, sparse_copy_async};
use proxmox_async::zip::{ZipEncoder, ZipEntry};

View File

@ -255,7 +255,7 @@ impl Flags {
/// Return the supported *pxar* feature flags based on the magic number of the filesystem.
pub fn from_magic(magic: i64) -> Flags {
use proxmox::sys::linux::magic::*;
use proxmox_sys::linux::magic::*;
match magic {
MSDOS_SUPER_MAGIC => {
Flags::WITH_2SEC_TIME |

View File

@ -25,8 +25,7 @@ use pxar::accessor::{self, EntryRangeInfo, ReadAt};
use proxmox_fuse::requests::{self, FuseRequest};
use proxmox_fuse::{EntryParam, Fuse, ReplyBufState, Request, ROOT_ID};
use pbs_tools::xattr;
use proxmox_sys::fs::xattr;
/// We mark inodes for regular files this way so we know how to access them.
const NON_DIRECTORY_INODE: u64 = 1u64 << 63;

View File

@ -9,11 +9,10 @@ use nix::sys::stat::Mode;
use pxar::Metadata;
use proxmox::c_result;
use proxmox::sys::error::SysError;
use proxmox::tools::fd::RawFdNum;
use pbs_tools::{acl, fs, xattr};
use proxmox_sys::c_result;
use proxmox_sys::error::SysError;
use proxmox_sys::fd::RawFdNum;
use proxmox_sys::fs::{self, acl, xattr};
use crate::pxar::tools::perms_from_metadata;
use crate::pxar::Flags;
@ -67,7 +66,7 @@ pub fn apply_at(
path_info: &Path,
on_error: &mut (dyn FnMut(Error) -> Result<(), Error> + Send),
) -> Result<(), Error> {
let fd = proxmox::tools::fd::Fd::openat(
let fd = proxmox_sys::fd::Fd::openat(
&unsafe { RawFdNum::from_raw_fd(parent) },
file_name,
OFlag::O_PATH | OFlag::O_CLOEXEC | OFlag::O_NOFOLLOW,

View File

@ -6,8 +6,8 @@ use std::io::Read;
use anyhow::{bail, format_err, Error};
use serde_json::Value;
use proxmox::sys::linux::tty;
use proxmox::tools::fs::file_get_contents;
use proxmox_sys::linux::tty;
use proxmox_sys::fs::file_get_contents;
use proxmox_schema::*;
use pbs_api_types::CryptMode;
@ -374,7 +374,7 @@ fn create_testdir(name: &str) -> Result<String, Error> {
// safe w.r.t. concurrency
fn test_crypto_parameters_handling() -> Result<(), Error> {
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 default_key = vec![2;1];

View File

@ -12,7 +12,7 @@ use xdg::BaseDirectories;
use proxmox_schema::*;
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_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 mut command = Command::new(&args[0]);
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)));
}
Err(NotUnicode(_)) => bail!(format!("{} contains bad characters", env_name)),

View File

@ -17,14 +17,14 @@ regex = "1.2"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
proxmox = "0.15.3"
proxmox-lang = "1"
proxmox-router = { version = "1.1", default-features = false }
proxmox-schema = "1"
proxmox-section-config = "1"
proxmox-time = "1"
proxmox-shared-memory = "0.1.1"
proxmox-sys = "0.1.2"
proxmox-serde = "0.1"
proxmox-shared-memory = "0.2"
proxmox-sys = "0.2"
pbs-api-types = { path = "../pbs-api-types" }
pbs-buildcfg = { path = "../pbs-buildcfg" }

View File

@ -7,7 +7,7 @@ use anyhow::{bail, Error};
use once_cell::sync::OnceCell;
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];
pub const PROXMOX_BACKUP_CONFIG_VERSION_CACHE_MAGIC_1_0: [u8; 8] = [25, 198, 168, 230, 154, 132, 143, 131];

View File

@ -36,7 +36,7 @@ pub fn lock_config() -> Result<BackupLockGuard, 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());
let digest = openssl::sha::sha256(content.as_bytes());

View File

@ -37,7 +37,7 @@ pub fn lock_config() -> Result<BackupLockGuard, 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());
let digest = openssl::sha::sha256(content.as_bytes());

View File

@ -71,7 +71,7 @@ pub fn lock() -> Result<BackupLockGuard, Error> {
/// Read and parse the configuration file
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());
let digest = openssl::sha::sha256(content.as_bytes());

View File

@ -4,7 +4,7 @@ use std::path::Path;
use anyhow::{bail, format_err, Context, Error};
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 pbs_api_types::{Kdf, KeyInfo, Fingerprint};
@ -18,12 +18,12 @@ pub enum KeyDerivationConfig {
n: u64,
r: u64,
p: u64,
#[serde(with = "proxmox::tools::serde::bytes_as_base64")]
#[serde(with = "proxmox_serde::bytes_as_base64")]
salt: Vec<u8>,
},
PBKDF2 {
iter: usize,
#[serde(with = "proxmox::tools::serde::bytes_as_base64")]
#[serde(with = "proxmox_serde::bytes_as_base64")]
salt: Vec<u8>,
},
}
@ -72,11 +72,11 @@ impl KeyDerivationConfig {
#[derive(Deserialize, Serialize, Clone, Debug)]
pub struct KeyConfig {
pub kdf: Option<KeyDerivationConfig>,
#[serde(with = "proxmox::tools::serde::epoch_as_rfc3339")]
#[serde(with = "proxmox_serde::epoch_as_rfc3339")]
pub created: i64,
#[serde(with = "proxmox::tools::serde::epoch_as_rfc3339")]
#[serde(with = "proxmox_serde::epoch_as_rfc3339")]
pub modified: i64,
#[serde(with = "proxmox::tools::serde::bytes_as_base64")]
#[serde(with = "proxmox_serde::bytes_as_base64")]
pub data: Vec<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
@ -111,7 +111,7 @@ impl KeyConfig {
/// Creates a new key using random data, protected by passphrase.
pub fn new(passphrase: &[u8], kdf: Kdf) -> Result<([u8;32], Self), Error> {
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)?;
Ok((key, key_config))
}
@ -144,7 +144,7 @@ impl KeyConfig {
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 {
Kdf::Scrypt => KeyDerivationConfig::Scrypt {
@ -166,7 +166,7 @@ impl KeyConfig {
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 encrypted_key = openssl::symm::encrypt_aead(

View File

@ -55,14 +55,14 @@ pub fn open_backup_lockfile<P: AsRef<std::path::Path>>(
exclusive: bool,
) -> Result<BackupLockGuard, Error> {
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))
.owner(user.uid)
.group(user.gid);
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)))
}
@ -77,12 +77,12 @@ pub fn replace_backup_config<P: AsRef<std::path::Path>>(
let mode = nix::sys::stat::Mode::from_bits_truncate(0o0640);
// set the correct owner/group/permissions while saving file
// owner(rw) = root, group(r)= backup
let options = proxmox::tools::fs::CreateOptions::new()
let options = proxmox_sys::fs::CreateOptions::new()
.perm(mode)
.owner(nix::unistd::ROOT)
.group(backup_user.gid);
proxmox::tools::fs::replace_file(path, data, options, true)?;
proxmox_sys::fs::replace_file(path, data, options, true)?;
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);
// set the correct owner/group/permissions while saving file
// owner(rw) = root, group(r)= root
let options = proxmox::tools::fs::CreateOptions::new()
let options = proxmox_sys::fs::CreateOptions::new()
.perm(mode)
.owner(nix::unistd::ROOT)
.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(())
}

View File

@ -49,7 +49,7 @@ pub fn lock() -> Result<BackupLockGuard, Error> {
/// Read and parse the configuration file
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());
let digest = openssl::sha::sha256(content.as_bytes());

View File

@ -9,8 +9,9 @@ use nix::ioctl_read_bad;
use nix::sys::socket::{socket, AddressFamily, SockType, SockFlag};
use regex::Regex;
use proxmox::*; // for IP macros
use proxmox::tools::fd::Fd;
use pbs_api_types::*; // for IP macros
use proxmox_sys::fd::Fd;
pub static IPV4_REVERSE_MASK: &[&str] = &[
"0.0.0.0",
@ -188,7 +189,7 @@ pub fn compute_file_diff(filename: &str, shadow: &str) -> Result<String, Error>
.output()
.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))?;
Ok(diff)
@ -209,7 +210,7 @@ pub fn network_reload() -> Result<(), Error> {
.output()
.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))?;

View File

@ -6,7 +6,7 @@ use serde::de::{value, IntoDeserializer, Deserialize};
use lazy_static::lazy_static;
use regex::Regex;
use proxmox::tools::{fs::replace_file, fs::CreateOptions};
use proxmox_sys::{fs::replace_file, fs::CreateOptions};
mod helper;
pub use helper::*;
@ -409,10 +409,10 @@ pub fn lock_config() -> Result<BackupLockGuard, 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,
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()
}
};

View File

@ -184,7 +184,7 @@ impl <R: BufRead> NetworkParser<R> {
self.eat(Token::Gateway)?;
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(':') {
set_gateway_v6(interface, gateway)?;
} else {

View File

@ -37,7 +37,7 @@ pub fn lock_config() -> Result<BackupLockGuard, 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());
let digest = openssl::sha::sha256(content.as_bytes());

View File

@ -38,7 +38,7 @@ pub fn lock_config() -> Result<BackupLockGuard, 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());
let digest = openssl::sha::sha256(content.as_bytes());

View File

@ -15,7 +15,7 @@ use std::collections::HashMap;
use anyhow::{bail, Error};
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 crate::key_config::KeyConfig;
@ -23,6 +23,7 @@ use crate::{open_backup_lockfile, replace_secret_config, replace_backup_config};
mod hex_key {
use serde::{self, Deserialize, Serializer, Deserializer};
use hex::FromHex;
pub fn serialize<S>(
csum: &[u8; 32],
@ -31,7 +32,7 @@ mod hex_key {
where
S: Serializer,
{
let s = proxmox::tools::digest_to_hex(csum);
let s = hex::encode(csum);
serializer.serialize_str(&s)
}
@ -42,7 +43,7 @@ mod hex_key {
D: Deserializer<'de>,
{
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)
}
}

View File

@ -36,7 +36,7 @@ pub fn lock() -> Result<BackupLockGuard, 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());
let digest = openssl::sha::sha256(content.as_bytes());

View File

@ -4,7 +4,7 @@ use anyhow::{bail, format_err, Error};
use serde::{Serialize, Deserialize};
use serde_json::{from_value, Value};
use proxmox::tools::fs::CreateOptions;
use proxmox_sys::fs::CreateOptions;
use pbs_api_types::Authid;
//use crate::auth;
@ -27,7 +27,7 @@ fn lock_config() -> Result<BackupLockGuard, 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 {
Ok(HashMap::new())
@ -45,7 +45,7 @@ fn write_file(data: HashMap<Authid, String>) -> Result<(), Error> {
.group(backup_user.gid);
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)
}

View File

@ -44,7 +44,7 @@ pub fn lock_config() -> Result<BackupLockGuard, Error> {
/// Read and parse the configuration file
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());
let digest = openssl::sha::sha256(content.as_bytes());

View File

@ -49,7 +49,7 @@ pub fn lock_config() -> Result<BackupLockGuard, 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());
let digest = openssl::sha::sha256(content.as_bytes());

View File

@ -37,7 +37,7 @@ pub fn lock_config() -> Result<BackupLockGuard, 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 digest = openssl::sha::sha256(content.as_bytes());

View File

@ -11,6 +11,7 @@ base64 = "0.13"
crc32fast = "1"
endian_trait = { version = "0.6", features = [ "arrays" ] }
futures = "0.3"
hex = "0.4.3"
lazy_static = "1.4"
libc = "0.2"
log = "0.4"
@ -25,14 +26,13 @@ zstd = { version = "0.6", features = [ "bindgen" ] }
pathpatterns = "0.1.2"
pxar = "0.10.1"
proxmox = "0.15.3"
proxmox-borrow = "1"
proxmox-io = "1"
proxmox-lang = "1"
proxmox-schema = { version = "1", features = [ "api-macro" ] }
proxmox-time = "1"
proxmox-uuid = "1"
proxmox-sys = "0.1.2"
proxmox-sys = "0.2"
pbs-api-types = { path = "../pbs-api-types" }
pbs-tools = { path = "../pbs-tools" }

View File

@ -81,7 +81,7 @@ impl BackupGroup {
let mut path = base_path.to_owned();
path.push(self.group_path());
pbs_tools::fs::scandir(
proxmox_sys::fs::scandir(
libc::AT_FDCWD,
&path,
&BACKUP_DATE_REGEX,
@ -110,7 +110,7 @@ impl BackupGroup {
let mut path = base_path.to_owned();
path.push(self.group_path());
pbs_tools::fs::scandir(
proxmox_sys::fs::scandir(
libc::AT_FDCWD,
&path,
&BACKUP_DATE_REGEX,
@ -369,7 +369,7 @@ impl BackupInfo {
pub fn list_backup_groups(base_path: &Path) -> Result<Vec<BackupGroup>, Error> {
let mut list = Vec::new();
pbs_tools::fs::scandir(
proxmox_sys::fs::scandir(
libc::AT_FDCWD,
base_path,
&BACKUP_TYPE_REGEX,
@ -377,7 +377,7 @@ impl BackupInfo {
if file_type != nix::dir::Type::Directory {
return Ok(());
}
pbs_tools::fs::scandir(
proxmox_sys::fs::scandir(
l0_fd,
backup_type,
&BACKUP_ID_REGEX,
@ -411,7 +411,7 @@ fn list_backup_files<P: ?Sized + nix::NixPath>(
) -> Result<Vec<String>, Error> {
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 {
return Ok(());
}

View File

@ -10,8 +10,8 @@ use anyhow::Error;
use futures::ready;
use tokio::io::{AsyncRead, AsyncSeek, ReadBuf};
use proxmox::io_format_err;
use proxmox::sys::error::io_err_other;
use proxmox_sys::io_format_err;
use proxmox_sys::error::io_err_other;
use pbs_tools::async_lru_cache::{AsyncCacher, AsyncLruCache};

View File

@ -5,9 +5,9 @@ use std::sync::{Arc, Mutex};
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::worker_task_context::WorkerTaskContext;
use proxmox_sys::WorkerTaskContext;
use proxmox_sys::task_log;
use pbs_api_types::GarbageCollectionStatus;
@ -96,7 +96,7 @@ impl ChunkStore {
// create lock file with correct owner/group
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
let mut last_percentage = 0;
@ -194,7 +194,7 @@ impl ChunkStore {
pub fn get_chunk_iterator(
&self,
) -> 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
> {
use nix::dir::Dir;
@ -212,7 +212,7 @@ impl ChunkStore {
})?;
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 percentage = 0;
Ok(std::iter::from_fn(move || {
@ -256,7 +256,7 @@ impl ChunkStore {
let subdir: &str = &format!("{:04x}", at);
percentage = (at * 100) / 0x10000;
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) => {
inner = Some(dir);
// start reading:
@ -382,7 +382,7 @@ impl ChunkStore {
digest: &[u8; 32],
) -> 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);
@ -440,7 +440,7 @@ impl ChunkStore {
let mut chunk_path = self.chunk_dir.clone();
let prefix = digest_to_prefix(digest);
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, digest_str)
}

View File

@ -17,7 +17,7 @@ impl <W: Write> CryptWriter<W> {
pub fn new(writer: W, config: Arc<CryptConfig>) -> Result<Self, Error> {
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 crypter = config.data_crypter(&iv, openssl::symm::Mode::Encrypt)?;

View File

@ -347,7 +347,7 @@ impl DataBlob {
) -> Result<([u8;16], [u8;16]), Error> {
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];

View File

@ -9,13 +9,13 @@ use std::time::Duration;
use anyhow::{bail, format_err, Error};
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::worker_task_context::WorkerTaskContext;
use proxmox_sys::WorkerTaskContext;
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_tools::fs::{lock_dir_noblock, DirLockGuard};
use pbs_config::{open_backup_lockfile, BackupLockGuard};
use crate::DataBlob;
@ -127,7 +127,7 @@ impl DataStore {
pub fn get_chunk_iterator(
&self,
) -> Result<
impl Iterator<Item = (Result<pbs_tools::fs::ReadDirEntry, Error>, usize, bool)>,
impl Iterator<Item = (Result<proxmox_sys::fs::ReadDirEntry, Error>, usize, bool)>,
Error
> {
self.chunk_store.get_chunk_iterator()
@ -199,7 +199,7 @@ impl DataStore {
map_err(|err| {
format_err!(
"fast_index_verification error, stat_chunk {} failed - {}",
proxmox::tools::digest_to_hex(&info.digest),
hex::encode(&info.digest),
err,
)
})?;
@ -232,7 +232,7 @@ impl DataStore {
wanted_files.insert(CLIENT_LOG_BLOB_NAME.to_string());
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 Some(file_type) = item.file_type() {
if file_type != nix::dir::Type::File { continue; }
@ -272,7 +272,7 @@ impl DataStore {
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);
@ -358,7 +358,7 @@ impl DataStore {
let mut full_path = self.base_path();
full_path.push(backup_group.group_path());
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
}
@ -525,7 +525,7 @@ impl DataStore {
task_warn!(
worker,
"warning: unable to access non-existent chunk {}, required by {:?}",
proxmox::tools::digest_to_hex(digest),
hex::encode(digest),
file_name,
);

View File

@ -9,7 +9,7 @@ use std::task::Context;
use anyhow::{bail, format_err, Error};
use proxmox::tools::mmap::Mmap;
use proxmox_sys::mmap::Mmap;
use proxmox_io::ReadExt;
use proxmox_uuid::Uuid;
use proxmox_sys::process_locker::ProcessLockSharedGuard;
@ -467,7 +467,7 @@ impl DynamicChunkWriter {
chunk_size,
(compressed_size * 100) / (chunk_size as u64),
is_duplicate,
proxmox::tools::digest_to_hex(&digest)
hex::encode(&digest)
);
self.index.add_chunk(self.chunk_offset as u64, &digest)?;
self.chunk_buffer.truncate(0);

View File

@ -424,7 +424,7 @@ impl FixedIndexWriter {
chunk_len,
(compressed_size * 100) / (chunk_len as u64),
is_duplicate,
proxmox::tools::digest_to_hex(digest)
hex::encode(digest)
);
if is_duplicate {

View File

@ -18,6 +18,7 @@ pub const ENCRYPTED_KEY_BLOB_NAME: &str = "rsa-encrypted.key.blob";
mod hex_csum {
use serde::{self, Deserialize, Serializer, Deserializer};
use hex::FromHex;
pub fn serialize<S>(
csum: &[u8; 32],
@ -26,7 +27,7 @@ mod hex_csum {
where
S: Serializer,
{
let s = proxmox::tools::digest_to_hex(csum);
let s = hex::encode(csum);
serializer.serialize_str(&s)
}
@ -37,7 +38,7 @@ mod hex_csum {
D: Deserializer<'de>,
{
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 {
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());
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(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"];
if fingerprint != &Value::Null {
@ -318,7 +319,7 @@ fn test_manifest_signature() -> Result<(), Error> {
assert_eq!(signature, "d7b446fb7db081662081d4b40fedd858a1d6307a5aff4ecff7d5bf4fd35679e9");
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);

View File

@ -247,7 +247,7 @@ fn generate_qr_code(output_type: &str, lines: &[String]) -> Result<Vec<u8>, Erro
.wait_with_output()
.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)
}

View File

@ -6,13 +6,14 @@ use std::fs::File;
use anyhow::{bail, Error};
use nix::dir::Dir;
use proxmox_sys::fs::lock_dir_noblock_shared;
use crate::backup_info::BackupDir;
use crate::index::IndexFile;
use crate::fixed_index::FixedIndexReader;
use crate::dynamic_index::DynamicIndexReader;
use crate::manifest::{archive_type, ArchiveType, CLIENT_LOG_BLOB_NAME, MANIFEST_BLOB_NAME};
use crate::DataStore;
use pbs_tools::fs::lock_dir_noblock_shared;
/// Helper to access the contents of a datastore backup snapshot
///

View File

@ -16,5 +16,4 @@ tokio = { version = "1.6", features = [] }
proxmox-time = "1"
proxmox-fuse = "0.1.1"
pbs-tools = { path = "../pbs-tools" }
proxmox-sys = "0.2"

View File

@ -304,7 +304,7 @@ fn emerg_cleanup(loopdev: Option<&str>, mut backing_file: PathBuf) {
let mut command = std::process::Command::new("fusermount");
command.arg("-u");
command.arg(&backing_file);
let _ = pbs_tools::run_command(command, None);
let _ = proxmox_sys::command::run_command(command, None);
let _ = remove_file(&backing_file);
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> {
// get map of all /dev/loop mappings belonging to us
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 {
let loopdev = format!("/dev/{}", ent.file_name().to_string_lossy());
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(
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 {
Ok(ent) => {
let file = ent.file_name().to_string_lossy();

View File

@ -11,6 +11,7 @@ libc = "0.2"
anyhow = "1.0"
thiserror = "1.0"
endian_trait = { version = "0.6", features = ["arrays"] }
hex = "0.4.3"
nix = "0.19.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
@ -18,7 +19,6 @@ bitflags = "1.2.1"
regex = "1.2"
udev = "0.4"
proxmox = "0.15.3"
proxmox-io = "1"
proxmox-lang = "1"
# 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
proxmox-router = "1.1"
proxmox-sys = "0.2"
pbs-api-types = { path = "../pbs-api-types" }
pbs-tools = { path = "../pbs-tools" }

View File

@ -69,11 +69,11 @@ impl <R: BlockRead> BlockedReader<R> {
fn check_buffer(buffer: &BlockHeader, seq_nr: u32) -> Result<(usize, bool), std::io::Error> {
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() {
proxmox::io_bail!(
proxmox_sys::io_bail!(
"detected tape block with wrong sequence number ({} != {})",
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);
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 {
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)?;
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(())
@ -113,13 +113,13 @@ impl <R: BlockRead> BlockedReader<R> {
let mut tmp_buf = [0u8; 512]; // use a small buffer for testing EOF
match reader.read_block(&mut tmp_buf) {
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) => {
return Ok(());
}
Err(BlockReadError::EndOfStream) => {
proxmox::io_bail!("got unexpected end of tape");
proxmox_sys::io_bail!("got unexpected end of tape");
}
Err(BlockReadError::Error(err)) => {
return Err(err);
@ -135,12 +135,12 @@ impl <R: BlockRead> BlockedReader<R> {
self.got_eod = true;
self.read_pos = self.buffer.payload.len();
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
}
Err(BlockReadError::EndOfStream) => {
proxmox::io_bail!("got unexpected end of tape");
proxmox_sys::io_bail!("got unexpected end of tape");
}
Err(BlockReadError::Error(err)) => {
return Err(err);
@ -167,10 +167,10 @@ impl <R: BlockRead> TapeRead for BlockedReader<R> {
fn is_incomplete(&self) -> Result<bool, std::io::Error> {
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 {
proxmox::io_bail!("is_incomplete failed: no end marker found");
proxmox_sys::io_bail!("is_incomplete failed: no end marker found");
}
Ok(self.incomplete)
@ -178,7 +178,7 @@ impl <R: BlockRead> TapeRead for BlockedReader<R> {
fn has_end_marker(&self) -> Result<bool, std::io::Error> {
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)
@ -207,7 +207,7 @@ impl <R: BlockRead> Read for BlockedReader<R> {
fn read(&mut self, buffer: &mut [u8]) -> Result<usize, std::io::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();
@ -299,7 +299,7 @@ mod test {
#[test]
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)
}
@ -323,7 +323,7 @@ mod test {
let writer = EmulateTapeWriter::new(&mut tape_data, 1024*1024);
let mut writer = BlockedWriter::new(writer);
// 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)?;
// but do not call finish here
}

View File

@ -65,7 +65,7 @@ impl <W: BlockWrite> BlockedWriter<W> {
fn write_eof(&mut self) -> Result<(), std::io::Error> {
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;

View File

@ -22,7 +22,7 @@ impl <R: Read> EmulateTapeReader<R> {
impl <R: Read> BlockRead for EmulateTapeReader<R> {
fn read_block(&mut self, buffer: &mut [u8]) -> Result<usize, BlockReadError> {
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)? {
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)
if buffer.len() != PROXMOX_TAPE_BLOCK_SIZE {
return Err(BlockReadError::Error(
proxmox::io_format_err!(
proxmox_sys::io_format_err!(
"EmulateTapeReader: read_block with wrong block size ({} != {})",
buffer.len(),
PROXMOX_TAPE_BLOCK_SIZE,

View File

@ -39,7 +39,7 @@ impl <W: Write> BlockWrite for EmulateTapeWriter<W> {
fn write_block(&mut self, buffer: &[u8]) -> Result<bool, io::Error> {
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);
}
@ -59,7 +59,7 @@ impl <W: Write> BlockWrite for EmulateTapeWriter<W> {
fn write_filemark(&mut self) -> Result<(), std::io::Error> {
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
self.wrote_eof = true;

View File

@ -7,9 +7,9 @@ use std::os::unix::io::AsRawFd;
use anyhow::{bail, format_err, Error};
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};
lazy_static::lazy_static!{

View File

@ -25,7 +25,7 @@ pub use mam::*;
mod report_density;
pub use report_density::*;
use proxmox::sys::error::SysResult;
use proxmox_sys::error::SysResult;
use proxmox_io::{ReadExt, WriteExt};
use pbs_api_types::{MamAttribute, Lp17VolumeStatistics, LtoDriveAndMediaStatus};
@ -530,11 +530,11 @@ impl SgTape {
) -> Result<(), std::io::Error> {
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)
.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);
let mut cmd = Vec::new();
@ -553,7 +553,7 @@ impl SgTape {
/* LEOM - ignore */
}
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();
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)
@ -656,7 +656,7 @@ impl SgTape {
return Ok(true); // LEOM
}
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 {
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) => {
return Err(BlockReadError::Error(
proxmox::io_format_err!("read failed - {}", err)
proxmox_sys::io_format_err!("read failed - {}", err)
));
}
};
if data.len() != transfer_len {
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> {
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) {
Ok(usize) => Ok(usize),

View File

@ -175,7 +175,7 @@ fn decode_mam_attributes(data: &[u8]) -> Result<Vec<MamAttribute>, Error> {
unreachable!();
}
},
MamFormat::BINARY => proxmox::tools::digest_to_hex(&data),
MamFormat::BINARY => hex::encode(&data),
};
list.push(MamAttribute {
id: head_id,

View File

@ -34,7 +34,7 @@ pub trait TapeWrite {
data: &[u8],
) -> Result<bool, std::io::Error> {
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();

View File

@ -32,12 +32,13 @@ url = "2.1"
walkdir = "2"
zstd = { version = "0.6", features = [ "bindgen" ] }
proxmox = { version = "0.15.3", default-features = false, features = [ "tokio" ] }
proxmox-async = "0.2"
#proxmox = { version = "0.15.3", default-features = false, features = [ "tokio" ] }
proxmox-async = "0.3"
proxmox-borrow = "1"
proxmox-io = { version = "1", features = [ "tokio" ] }
proxmox-lang = { version = "1" }
proxmox-time = { version = "1" }
proxmox-sys = "0.2"
pbs-buildcfg = { path = "../pbs-buildcfg" }
pbs-api-types = { path = "../pbs-api-types" }

View File

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

View File

@ -41,7 +41,7 @@ fn x509name_to_string(name: &openssl::x509::X509NameRef) -> Result<String, Error
impl CertInfo {
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))
}

View File

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

View File

@ -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: &regex::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)),
}))
}

View File

@ -1,6 +1,6 @@
//! I/O utilities.
use proxmox::tools::fd::Fd;
use proxmox_sys::fd::Fd;
/// The `BufferedRead` trait provides a single function
/// `buffered_read`. It returns a reference to an internal buffer. The

View File

@ -1,9 +1,7 @@
pub mod acl;
pub mod cert;
pub mod cli;
pub mod crypt_config;
pub mod format;
pub mod fs;
pub mod io;
pub mod json;
pub mod lru_cache;
@ -14,9 +12,5 @@ pub mod str;
pub mod sync;
pub mod sys;
pub mod ticket;
pub mod xattr;
pub mod async_lru_cache;
mod command;
pub use command::{command_output, command_output_as_string, run_command};

View File

@ -18,7 +18,7 @@ impl Write for StdChannelWriter {
fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
self.0
.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()))
}

View File

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

View File

@ -22,11 +22,12 @@ zstd = { version = "0.6", features = [ "bindgen" ] }
pathpatterns = "0.1.2"
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
proxmox = { version = "0.15.3", features = [ "sortable-macro" ] }
proxmox-async = "0.2"
proxmox-async = "0.3"
proxmox-router = { version = "1.1", features = [ "cli" ] }
proxmox-schema = { version = "1", features = [ "api-macro" ] }
proxmox-time = "1"
proxmox-sys = { version = "0.2", features = [ "sortable-macro" ] }
pbs-api-types = { path = "../pbs-api-types" }
pbs-buildcfg = { path = "../pbs-buildcfg" }

View File

@ -267,7 +267,7 @@ fn test_crypt_speed(
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![];
// generate pseudo random byte sequence
for i in 0..256*1024 {

View File

@ -4,8 +4,8 @@ use std::path::PathBuf;
use anyhow::{bail, format_err, Error};
use serde_json::Value;
use proxmox::sys::linux::tty;
use proxmox::tools::fs::{file_get_contents, replace_file, CreateOptions};
use proxmox_sys::linux::tty;
use proxmox_sys::fs::{file_get_contents, replace_file, CreateOptions};
use proxmox_router::cli::{
complete_file_name, format_and_print_result_full, get_output_format,
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 mut key = [0u8; 32];
proxmox::sys::linux::fill_with_random_data(&mut key)?;
proxmox_sys::linux::fill_with_random_data(&mut key)?;
match kdf {
Kdf::None => {

View File

@ -13,7 +13,7 @@ use tokio_stream::wrappers::ReceiverStream;
use xdg::BaseDirectories;
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_schema::api;
use proxmox_time::{strftime_local, epoch_i64};
@ -654,7 +654,7 @@ async fn create_backup(
let crypto = crypto_parameters(&param)?;
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");
@ -751,7 +751,7 @@ async fn create_backup(
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();

View File

@ -13,8 +13,8 @@ use nix::unistd::{fork, ForkResult};
use serde_json::Value;
use tokio::signal::unix::{signal, SignalKind};
use proxmox::{sortable, identity};
use proxmox::tools::fd::Fd;
use proxmox_sys::{sortable, identity};
use proxmox_sys::fd::Fd;
use proxmox_router::{ApiHandler, ApiMethod, RpcEnvironment, cli::*};
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() {
Ok(mappings) => mappings
.filter_map(|(name, _)| {
proxmox::tools::systemd::unescape_unit(&name).ok()
proxmox_sys::systemd::unescape_unit(&name).ok()
}).collect(),
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 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 loopdev = session.loopdev_path.clone();
@ -342,7 +342,7 @@ fn unmap(
pbs_fuse_loop::cleanup_unused_run_files(None);
let mut any = false;
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);
any = true;
}
@ -361,7 +361,7 @@ fn unmap(
if name.starts_with("/dev/loop") {
pbs_fuse_loop::unmap_loopdev(name)?;
} 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)?;
}

View File

@ -3,7 +3,7 @@ use std::sync::Arc;
use anyhow::Error;
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_schema::api;

View File

@ -16,14 +16,14 @@ tokio = { version = "1.6", features = [ "io-std", "rt", "rt-multi-thread", "time
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
proxmox = { version = "0.15.3" }
proxmox-async = "0.2"
#proxmox = { version = "0.15.3" }
proxmox-async = "0.3"
proxmox-lang = "1"
proxmox-router = { version = "1.1", features = [ "cli" ] }
proxmox-schema = { version = "1", features = [ "api-macro" ] }
proxmox-time = "1"
proxmox-uuid = "1"
proxmox-sys = "0.1.2"
proxmox-sys = "0.2"
pbs-api-types = { path = "../pbs-api-types" }
pbs-buildcfg = { path = "../pbs-buildcfg" }

View File

@ -8,7 +8,7 @@ use futures::FutureExt;
use serde::{Deserialize, Serialize};
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_datastore::backup_info::BackupDir;
@ -80,7 +80,7 @@ impl VMStateMap {
fn make_name(repo: &BackupRepository, snap: &BackupDir) -> String {
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
@ -257,7 +257,7 @@ impl BlockRestoreDriver for QemuBlockDriver {
let resp = client
.get("api2/json/status", Some(json!({"keep-timeout": true})))
.await;
let name = proxmox::tools::systemd::unescape_unit(n)
let name = proxmox_sys::systemd::unescape_unit(n)
.unwrap_or_else(|_| "<invalid name>".to_owned());
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>> {
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 map_mod = cleanup_map(&mut map.map).await;
match map.map.get(&name) {
@ -325,7 +325,7 @@ impl BlockRestoreDriver for QemuBlockDriver {
match VMStateMap::load_read_only() {
Ok(state) => state
.iter()
.filter_map(|(name, _)| proxmox::tools::systemd::unescape_unit(&name).ok())
.filter_map(|(name, _)| proxmox_sys::systemd::unescape_unit(&name).ok())
.collect(),
Err(_) => Vec::new(),
}

View File

@ -6,7 +6,7 @@ use std::sync::Arc;
use anyhow::{bail, format_err, Error};
use serde_json::{json, Value};
use proxmox::tools::fs::{create_path, CreateOptions};
use proxmox_sys::fs::{create_path, CreateOptions};
use proxmox_router::cli::{
complete_file_name, default_table_format_options,
format_and_print_result_full, get_output_format,

View File

@ -11,8 +11,8 @@ use tokio::time;
use nix::sys::signal::{kill, Signal};
use nix::unistd::Pid;
use proxmox::tools::fs::{create_path, file_read_string, make_tmp_file, CreateOptions};
use proxmox::tools::fd::fd_change_cloexec;
use proxmox_sys::fs::{create_path, file_read_string, make_tmp_file, CreateOptions};
use proxmox_sys::fd::fd_change_cloexec;
use proxmox_sys::logrotate::LogRotate;
use pbs_client::{VsockClient, DEFAULT_VSOCK_PORT};

View File

@ -30,12 +30,12 @@ tokio-openssl = "0.6.1"
tower-service = "0.3.0"
url = "2.1"
proxmox = "0.15.3"
proxmox-async = "0.2"
#proxmox = "0.15.3"
proxmox-async = "0.3"
proxmox-io = "1"
proxmox-lang = "1"
proxmox-http = { version = "0.5.0", features = [ "client" ] }
proxmox-http = { version = "0.6", features = [ "client" ] }
proxmox-router = "1.1"
proxmox-schema = { version = "1", features = [ "api-macro", "upid-api-impl" ] }
proxmox-time = "1"
proxmox-sys = "0.1.2"
proxmox-sys = "0.2"

View File

@ -12,7 +12,7 @@ use hyper::http::request::Parts;
use handlebars::Handlebars;
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 crate::{ServerAdapter, AuthError, FileLogger, FileLogOptions, CommandSocket, RestEnvironment};

View File

@ -13,7 +13,7 @@ use anyhow::{bail, format_err, Error};
use futures::future::{self, Either};
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};
// 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 fd = unsafe { sd_journal_stream_fd(ident.as_ptr(), libc::LOG_INFO, 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)?;
} else {
log::error!("failed to update STDOUT journal redirection ({})", fd);
}
let fd = unsafe { sd_journal_stream_fd(ident.as_ptr(), libc::LOG_ERR, 1) };
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)?;
} else {
log::error!("failed to update STDERR journal redirection ({})", fd);

View File

@ -3,7 +3,7 @@ use std::io::Write;
use anyhow::Error;
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
#[derive(Default)]

View File

@ -25,9 +25,9 @@ use hyper::{Body, Response, Method};
use http::request::Parts;
use http::HeaderMap;
use proxmox::tools::fd::Fd;
use proxmox::sys::linux::procfs::PidStat;
use proxmox::tools::fs::CreateOptions;
use proxmox_sys::fd::Fd;
use proxmox_sys::linux::procfs::PidStat;
use proxmox_sys::fs::CreateOptions;
use proxmox_router::UserInformation;
mod compression;
@ -117,12 +117,12 @@ pub(crate) fn pstart() -> u64 {
/// Helper to write the PID into a file
pub fn write_pid(pid_fn: &str) -> Result<(), Error> {
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
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();
pid.parse().map_err(|err| format_err!("could not parse pid - {}", err))
}

View File

@ -479,7 +479,7 @@ pub(crate) async fn handle_api_request<Env: RpcEnvironment, S: 'static + BuildHa
resp.map(|body| {
Body::wrap_stream(DeflateEncoder::with_quality(
TryStreamExt::map_err(body, |err| {
proxmox::io_format_err!("error during compression: {}", err)
proxmox_sys::io_format_err!("error during compression: {}", err)
}),
Level::Default,
))

View File

@ -16,12 +16,12 @@ use tokio::sync::oneshot;
use nix::fcntl::OFlag;
use once_cell::sync::OnceCell;
use proxmox::sys::linux::procfs;
use proxmox::tools::fs::{create_path, replace_file, atomic_open_or_create_file, CreateOptions};
use proxmox_sys::linux::procfs;
use proxmox_sys::fs::{create_path, replace_file, atomic_open_or_create_file, CreateOptions};
use proxmox_lang::try_block;
use proxmox_schema::upid::UPID;
use proxmox_sys::worker_task_context::{WorkerTaskContext};
use proxmox_sys::WorkerTaskContext;
use proxmox_sys::logrotate::{LogRotate, LogRotateFiles};
use crate::{CommandSocket, FileLogger, FileLogOptions};
@ -79,7 +79,7 @@ impl WorkerTaskSetup {
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,
timeout,
exclusive,

View File

@ -26,11 +26,11 @@ tokio-util = { version = "0.6", features = [ "codec", "io" ] }
pathpatterns = "0.1.2"
pxar = { version = "0.10.1", features = [ "tokio-io" ] }
proxmox = { version = "0.15.3", features = [ "sortable-macro" ] }
proxmox-async = "0.2"
proxmox-async = "0.3"
proxmox-router = { version = "1.1", features = [ "cli" ] }
proxmox-schema = { version = "1", features = [ "api-macro" ] }
proxmox-time = "1"
proxmox-sys = { version = "0.2", features = [ "sortable-macro" ] }
pbs-api-types = { path = "../pbs-api-types" }
pbs-tools = { path = "../pbs-tools" }

View File

@ -13,18 +13,18 @@ use serde_json::Value;
use tokio::sync::Semaphore;
use pathpatterns::{MatchEntry, MatchPattern, MatchType, Pattern};
use proxmox::{identity, sortable};
use proxmox_router::{
list_subdirs_api_method,
ApiHandler, ApiMethod, ApiResponseFuture, Permission, Router, RpcEnvironment, SubdirMap,
};
use proxmox_schema::*;
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_client::pxar::{create_archive, Flags, PxarCreateOptions, ENCODER_MAX_ENTRIES};
use pbs_datastore::catalog::{ArchiveEntry, DirEntryAttribute};
use pbs_tools::fs::read_subdir;
use pbs_tools::json::required_string_param;
use pxar::encoder::aio::TokioWriter;

View File

@ -9,11 +9,11 @@ use anyhow::{bail, format_err, Error};
use lazy_static::lazy_static;
use log::{info, warn};
use proxmox::tools::fs;
use proxmox_sys::fs;
use proxmox_sys::command::run_command;
use proxmox_schema::const_regex;
use pbs_api_types::BLOCKDEVICE_NAME_REGEX;
use pbs_tools::run_command;
const_regex! {
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)
// 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,
"/sys/block",
&BLOCKDEVICE_NAME_REGEX,
@ -416,7 +416,7 @@ impl DiskState {
}
let mut parts = Vec::new();
for entry in pbs_tools::fs::scan_subdir(
for entry in proxmox_sys::fs::scan_subdir(
libc::AT_FDCWD,
sys_path,
&VIRTIO_PART_REGEX,

View File

@ -19,6 +19,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
serde_cbor = "0.11.1"
proxmox = { version = "0.15.3" }
#proxmox = { version = "0.15.3" }
proxmox-time = "1"
proxmox-schema = { version = "1", features = [ "api-macro" ] }
proxmox-sys = "0.2"

View File

@ -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::{ApiStringFormat, ApiType, IntegerSchema, Schema, StringSchema};
use proxmox::tools::fs::CreateOptions;
use proxmox_sys::fs::CreateOptions;
use proxmox_rrd::rrd::{CF, DST, RRA, RRD};

View File

@ -10,7 +10,7 @@ use std::collections::BTreeSet;
use crossbeam_channel::{bounded, TryRecvError};
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};

View File

@ -10,7 +10,7 @@ use anyhow::{bail, format_err, Error};
use nix::fcntl::OFlag;
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";

Some files were not shown because too many files have changed in this diff Show More