BackupDir: make constructor fallible
since converting from i64 epoch timestamp to DateTime is not always possible. previously, passing invalid backup-time from client to server (or vice-versa) panicked the corresponding tokio task. now we get proper error messages including the invalid timestamp. Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
This commit is contained in:
parent
7158b304f5
commit
e0e5b4426a
@ -230,7 +230,7 @@ pub fn list_snapshot_files(
|
|||||||
|
|
||||||
let datastore = DataStore::lookup_datastore(&store)?;
|
let datastore = DataStore::lookup_datastore(&store)?;
|
||||||
|
|
||||||
let snapshot = BackupDir::new(backup_type, backup_id, backup_time);
|
let snapshot = BackupDir::new(backup_type, backup_id, backup_time)?;
|
||||||
|
|
||||||
let allowed = (user_privs & (PRIV_DATASTORE_AUDIT | PRIV_DATASTORE_READ)) != 0;
|
let allowed = (user_privs & (PRIV_DATASTORE_AUDIT | PRIV_DATASTORE_READ)) != 0;
|
||||||
if !allowed { check_backup_owner(&datastore, snapshot.group(), &userid)?; }
|
if !allowed { check_backup_owner(&datastore, snapshot.group(), &userid)?; }
|
||||||
@ -280,7 +280,7 @@ fn delete_snapshot(
|
|||||||
let user_info = CachedUserInfo::new()?;
|
let user_info = CachedUserInfo::new()?;
|
||||||
let user_privs = user_info.lookup_privs(&userid, &["datastore", &store]);
|
let user_privs = user_info.lookup_privs(&userid, &["datastore", &store]);
|
||||||
|
|
||||||
let snapshot = BackupDir::new(backup_type, backup_id, backup_time);
|
let snapshot = BackupDir::new(backup_type, backup_id, backup_time)?;
|
||||||
|
|
||||||
let datastore = DataStore::lookup_datastore(&store)?;
|
let datastore = DataStore::lookup_datastore(&store)?;
|
||||||
|
|
||||||
@ -490,7 +490,7 @@ pub fn verify(
|
|||||||
match (backup_type, backup_id, backup_time) {
|
match (backup_type, backup_id, backup_time) {
|
||||||
(Some(backup_type), Some(backup_id), Some(backup_time)) => {
|
(Some(backup_type), Some(backup_id), Some(backup_time)) => {
|
||||||
worker_id = format!("{}_{}_{}_{:08X}", store, backup_type, backup_id, backup_time);
|
worker_id = format!("{}_{}_{}_{:08X}", store, backup_type, backup_id, backup_time);
|
||||||
let dir = BackupDir::new(backup_type, backup_id, backup_time);
|
let dir = BackupDir::new(backup_type, backup_id, backup_time)?;
|
||||||
backup_dir = Some(dir);
|
backup_dir = Some(dir);
|
||||||
}
|
}
|
||||||
(Some(backup_type), Some(backup_id), None) => {
|
(Some(backup_type), Some(backup_id), None) => {
|
||||||
@ -897,7 +897,7 @@ fn download_file(
|
|||||||
let backup_id = tools::required_string_param(¶m, "backup-id")?;
|
let backup_id = tools::required_string_param(¶m, "backup-id")?;
|
||||||
let backup_time = tools::required_integer_param(¶m, "backup-time")?;
|
let backup_time = tools::required_integer_param(¶m, "backup-time")?;
|
||||||
|
|
||||||
let backup_dir = BackupDir::new(backup_type, backup_id, backup_time);
|
let backup_dir = BackupDir::new(backup_type, backup_id, backup_time)?;
|
||||||
|
|
||||||
let allowed = (user_privs & PRIV_DATASTORE_READ) != 0;
|
let allowed = (user_privs & PRIV_DATASTORE_READ) != 0;
|
||||||
if !allowed { check_backup_owner(&datastore, backup_dir.group(), &userid)?; }
|
if !allowed { check_backup_owner(&datastore, backup_dir.group(), &userid)?; }
|
||||||
@ -970,7 +970,7 @@ fn download_file_decoded(
|
|||||||
let backup_id = tools::required_string_param(¶m, "backup-id")?;
|
let backup_id = tools::required_string_param(¶m, "backup-id")?;
|
||||||
let backup_time = tools::required_integer_param(¶m, "backup-time")?;
|
let backup_time = tools::required_integer_param(¶m, "backup-time")?;
|
||||||
|
|
||||||
let backup_dir = BackupDir::new(backup_type, backup_id, backup_time);
|
let backup_dir = BackupDir::new(backup_type, backup_id, backup_time)?;
|
||||||
|
|
||||||
let allowed = (user_privs & PRIV_DATASTORE_READ) != 0;
|
let allowed = (user_privs & PRIV_DATASTORE_READ) != 0;
|
||||||
if !allowed { check_backup_owner(&datastore, backup_dir.group(), &userid)?; }
|
if !allowed { check_backup_owner(&datastore, backup_dir.group(), &userid)?; }
|
||||||
@ -1083,7 +1083,7 @@ fn upload_backup_log(
|
|||||||
let backup_id = tools::required_string_param(¶m, "backup-id")?;
|
let backup_id = tools::required_string_param(¶m, "backup-id")?;
|
||||||
let backup_time = tools::required_integer_param(¶m, "backup-time")?;
|
let backup_time = tools::required_integer_param(¶m, "backup-time")?;
|
||||||
|
|
||||||
let backup_dir = BackupDir::new(backup_type, backup_id, backup_time);
|
let backup_dir = BackupDir::new(backup_type, backup_id, backup_time)?;
|
||||||
|
|
||||||
let userid: Userid = rpcenv.get_user().unwrap().parse()?;
|
let userid: Userid = rpcenv.get_user().unwrap().parse()?;
|
||||||
check_backup_owner(&datastore, backup_dir.group(), &userid)?;
|
check_backup_owner(&datastore, backup_dir.group(), &userid)?;
|
||||||
@ -1159,7 +1159,7 @@ fn catalog(
|
|||||||
let user_info = CachedUserInfo::new()?;
|
let user_info = CachedUserInfo::new()?;
|
||||||
let user_privs = user_info.lookup_privs(&userid, &["datastore", &store]);
|
let user_privs = user_info.lookup_privs(&userid, &["datastore", &store]);
|
||||||
|
|
||||||
let backup_dir = BackupDir::new(backup_type, backup_id, backup_time);
|
let backup_dir = BackupDir::new(backup_type, backup_id, backup_time)?;
|
||||||
|
|
||||||
let allowed = (user_privs & PRIV_DATASTORE_READ) != 0;
|
let allowed = (user_privs & PRIV_DATASTORE_READ) != 0;
|
||||||
if !allowed { check_backup_owner(&datastore, backup_dir.group(), &userid)?; }
|
if !allowed { check_backup_owner(&datastore, backup_dir.group(), &userid)?; }
|
||||||
@ -1276,7 +1276,7 @@ fn pxar_file_download(
|
|||||||
let backup_id = tools::required_string_param(¶m, "backup-id")?;
|
let backup_id = tools::required_string_param(¶m, "backup-id")?;
|
||||||
let backup_time = tools::required_integer_param(¶m, "backup-time")?;
|
let backup_time = tools::required_integer_param(¶m, "backup-time")?;
|
||||||
|
|
||||||
let backup_dir = BackupDir::new(backup_type, backup_id, backup_time);
|
let backup_dir = BackupDir::new(backup_type, backup_id, backup_time)?;
|
||||||
|
|
||||||
let allowed = (user_privs & PRIV_DATASTORE_READ) != 0;
|
let allowed = (user_privs & PRIV_DATASTORE_READ) != 0;
|
||||||
if !allowed { check_backup_owner(&datastore, backup_dir.group(), &userid)?; }
|
if !allowed { check_backup_owner(&datastore, backup_dir.group(), &userid)?; }
|
||||||
@ -1417,7 +1417,7 @@ fn get_notes(
|
|||||||
let user_info = CachedUserInfo::new()?;
|
let user_info = CachedUserInfo::new()?;
|
||||||
let user_privs = user_info.lookup_privs(&userid, &["datastore", &store]);
|
let user_privs = user_info.lookup_privs(&userid, &["datastore", &store]);
|
||||||
|
|
||||||
let backup_dir = BackupDir::new(backup_type, backup_id, backup_time);
|
let backup_dir = BackupDir::new(backup_type, backup_id, backup_time)?;
|
||||||
|
|
||||||
let allowed = (user_privs & PRIV_DATASTORE_READ) != 0;
|
let allowed = (user_privs & PRIV_DATASTORE_READ) != 0;
|
||||||
if !allowed { check_backup_owner(&datastore, backup_dir.group(), &userid)?; }
|
if !allowed { check_backup_owner(&datastore, backup_dir.group(), &userid)?; }
|
||||||
@ -1470,7 +1470,7 @@ fn set_notes(
|
|||||||
let user_info = CachedUserInfo::new()?;
|
let user_info = CachedUserInfo::new()?;
|
||||||
let user_privs = user_info.lookup_privs(&userid, &["datastore", &store]);
|
let user_privs = user_info.lookup_privs(&userid, &["datastore", &store]);
|
||||||
|
|
||||||
let backup_dir = BackupDir::new(backup_type, backup_id, backup_time);
|
let backup_dir = BackupDir::new(backup_type, backup_id, backup_time)?;
|
||||||
|
|
||||||
let allowed = (user_privs & PRIV_DATASTORE_READ) != 0;
|
let allowed = (user_privs & PRIV_DATASTORE_READ) != 0;
|
||||||
if !allowed { check_backup_owner(&datastore, backup_dir.group(), &userid)?; }
|
if !allowed { check_backup_owner(&datastore, backup_dir.group(), &userid)?; }
|
||||||
|
@ -114,7 +114,7 @@ async move {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let last_backup = BackupInfo::last_backup(&datastore.base_path(), &backup_group, true).unwrap_or(None);
|
let last_backup = BackupInfo::last_backup(&datastore.base_path(), &backup_group, true).unwrap_or(None);
|
||||||
let backup_dir = BackupDir::new_with_group(backup_group.clone(), backup_time);
|
let backup_dir = BackupDir::new_with_group(backup_group.clone(), backup_time)?;
|
||||||
|
|
||||||
let _last_guard = if let Some(last) = &last_backup {
|
let _last_guard = if let Some(last) = &last_backup {
|
||||||
if backup_dir.backup_time() <= last.backup_dir.backup_time() {
|
if backup_dir.backup_time() <= last.backup_dir.backup_time() {
|
||||||
|
@ -83,7 +83,7 @@ fn upgrade_to_backup_reader_protocol(
|
|||||||
|
|
||||||
let env_type = rpcenv.env_type();
|
let env_type = rpcenv.env_type();
|
||||||
|
|
||||||
let backup_dir = BackupDir::new(backup_type, backup_id, backup_time);
|
let backup_dir = BackupDir::new(backup_type, backup_id, backup_time)?;
|
||||||
let path = datastore.base_path();
|
let path = datastore.base_path();
|
||||||
|
|
||||||
//let files = BackupInfo::list_files(&path, &backup_dir)?;
|
//let files = BackupInfo::list_files(&path, &backup_dir)?;
|
||||||
|
@ -2,9 +2,10 @@ use crate::tools;
|
|||||||
|
|
||||||
use anyhow::{bail, format_err, Error};
|
use anyhow::{bail, format_err, Error};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
use std::convert::TryFrom;
|
||||||
use std::os::unix::io::RawFd;
|
use std::os::unix::io::RawFd;
|
||||||
|
|
||||||
use chrono::{DateTime, TimeZone, SecondsFormat, Utc};
|
use chrono::{DateTime, LocalResult, TimeZone, SecondsFormat, Utc};
|
||||||
|
|
||||||
use std::path::{PathBuf, Path};
|
use std::path::{PathBuf, Path};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
@ -106,7 +107,7 @@ impl BackupGroup {
|
|||||||
if file_type != nix::dir::Type::Directory { return Ok(()); }
|
if file_type != nix::dir::Type::Directory { return Ok(()); }
|
||||||
|
|
||||||
let dt = backup_time.parse::<DateTime<Utc>>()?;
|
let dt = backup_time.parse::<DateTime<Utc>>()?;
|
||||||
let backup_dir = BackupDir::new(self.backup_type.clone(), self.backup_id.clone(), dt.timestamp());
|
let backup_dir = BackupDir::new(self.backup_type.clone(), self.backup_id.clone(), dt.timestamp())?;
|
||||||
let files = list_backup_files(l2_fd, backup_time)?;
|
let files = list_backup_files(l2_fd, backup_time)?;
|
||||||
|
|
||||||
list.push(BackupInfo { backup_dir, files });
|
list.push(BackupInfo { backup_dir, files });
|
||||||
@ -208,19 +209,22 @@ pub struct BackupDir {
|
|||||||
|
|
||||||
impl BackupDir {
|
impl BackupDir {
|
||||||
|
|
||||||
pub fn new<T, U>(backup_type: T, backup_id: U, timestamp: i64) -> Self
|
pub fn new<T, U>(backup_type: T, backup_id: U, timestamp: i64) -> Result<Self, Error>
|
||||||
where
|
where
|
||||||
T: Into<String>,
|
T: Into<String>,
|
||||||
U: Into<String>,
|
U: Into<String>,
|
||||||
{
|
{
|
||||||
// Note: makes sure that nanoseconds is 0
|
let group = BackupGroup::new(backup_type.into(), backup_id.into());
|
||||||
Self {
|
BackupDir::new_with_group(group, timestamp)
|
||||||
group: BackupGroup::new(backup_type.into(), backup_id.into()),
|
|
||||||
backup_time: Utc.timestamp(timestamp, 0),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub fn new_with_group(group: BackupGroup, timestamp: i64) -> Self {
|
|
||||||
Self { group, backup_time: Utc.timestamp(timestamp, 0) }
|
pub fn new_with_group(group: BackupGroup, timestamp: i64) -> Result<Self, Error> {
|
||||||
|
let backup_time = match Utc.timestamp_opt(timestamp, 0) {
|
||||||
|
LocalResult::Single(time) => time,
|
||||||
|
_ => bail!("can't create BackupDir with invalid backup time {}", timestamp),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self { group, backup_time })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn group(&self) -> &BackupGroup {
|
pub fn group(&self) -> &BackupGroup {
|
||||||
@ -257,7 +261,7 @@ impl std::str::FromStr for BackupDir {
|
|||||||
|
|
||||||
let group = BackupGroup::new(cap.get(1).unwrap().as_str(), cap.get(2).unwrap().as_str());
|
let group = BackupGroup::new(cap.get(1).unwrap().as_str(), cap.get(2).unwrap().as_str());
|
||||||
let backup_time = cap.get(3).unwrap().as_str().parse::<DateTime<Utc>>()?;
|
let backup_time = cap.get(3).unwrap().as_str().parse::<DateTime<Utc>>()?;
|
||||||
Ok(BackupDir::from((group, backup_time.timestamp())))
|
BackupDir::try_from((group, backup_time.timestamp()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,9 +274,11 @@ impl std::fmt::Display for BackupDir {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<(BackupGroup, i64)> for BackupDir {
|
impl TryFrom<(BackupGroup, i64)> for BackupDir {
|
||||||
fn from((group, timestamp): (BackupGroup, i64)) -> Self {
|
type Error = Error;
|
||||||
Self { group, backup_time: Utc.timestamp(timestamp, 0) }
|
|
||||||
|
fn try_from((group, timestamp): (BackupGroup, i64)) -> Result<Self, Error> {
|
||||||
|
BackupDir::new_with_group(group, timestamp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,7 +340,7 @@ impl BackupInfo {
|
|||||||
if file_type != nix::dir::Type::Directory { return Ok(()); }
|
if file_type != nix::dir::Type::Directory { return Ok(()); }
|
||||||
|
|
||||||
let dt = backup_time.parse::<DateTime<Utc>>()?;
|
let dt = backup_time.parse::<DateTime<Utc>>()?;
|
||||||
let backup_dir = BackupDir::new(backup_type, backup_id, dt.timestamp());
|
let backup_dir = BackupDir::new(backup_type, backup_id, dt.timestamp())?;
|
||||||
|
|
||||||
let files = list_backup_files(l2_fd, backup_time)?;
|
let files = list_backup_files(l2_fd, backup_time)?;
|
||||||
|
|
||||||
|
@ -377,7 +377,7 @@ async fn list_backup_groups(param: Value) -> Result<Value, Error> {
|
|||||||
|
|
||||||
let render_last_backup = |_v: &Value, record: &Value| -> Result<String, Error> {
|
let render_last_backup = |_v: &Value, record: &Value| -> Result<String, Error> {
|
||||||
let item: GroupListItem = serde_json::from_value(record.to_owned())?;
|
let item: GroupListItem = serde_json::from_value(record.to_owned())?;
|
||||||
let snapshot = BackupDir::new(item.backup_type, item.backup_id, item.last_backup);
|
let snapshot = BackupDir::new(item.backup_type, item.backup_id, item.last_backup)?;
|
||||||
Ok(snapshot.relative_path().to_str().unwrap().to_owned())
|
Ok(snapshot.relative_path().to_str().unwrap().to_owned())
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -448,7 +448,7 @@ async fn list_snapshots(param: Value) -> Result<Value, Error> {
|
|||||||
|
|
||||||
let render_snapshot_path = |_v: &Value, record: &Value| -> Result<String, Error> {
|
let render_snapshot_path = |_v: &Value, record: &Value| -> Result<String, Error> {
|
||||||
let item: SnapshotListItem = serde_json::from_value(record.to_owned())?;
|
let item: SnapshotListItem = serde_json::from_value(record.to_owned())?;
|
||||||
let snapshot = BackupDir::new(item.backup_type, item.backup_id, item.backup_time);
|
let snapshot = BackupDir::new(item.backup_type, item.backup_id, item.backup_time)?;
|
||||||
Ok(snapshot.relative_path().to_str().unwrap().to_owned())
|
Ok(snapshot.relative_path().to_str().unwrap().to_owned())
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1047,7 +1047,7 @@ async fn create_backup(
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let snapshot = BackupDir::new(backup_type, backup_id, backup_time.timestamp());
|
let snapshot = BackupDir::new(backup_type, backup_id, backup_time.timestamp())?;
|
||||||
let mut manifest = BackupManifest::new(snapshot);
|
let mut manifest = BackupManifest::new(snapshot);
|
||||||
|
|
||||||
let mut catalog = None;
|
let mut catalog = None;
|
||||||
@ -1572,7 +1572,7 @@ async fn prune_async(mut param: Value) -> Result<Value, Error> {
|
|||||||
|
|
||||||
let render_snapshot_path = |_v: &Value, record: &Value| -> Result<String, Error> {
|
let render_snapshot_path = |_v: &Value, record: &Value| -> Result<String, Error> {
|
||||||
let item: PruneListItem = serde_json::from_value(record.to_owned())?;
|
let item: PruneListItem = serde_json::from_value(record.to_owned())?;
|
||||||
let snapshot = BackupDir::new(item.backup_type, item.backup_id, item.backup_time);
|
let snapshot = BackupDir::new(item.backup_type, item.backup_id, item.backup_time)?;
|
||||||
Ok(snapshot.relative_path().to_str().unwrap().to_owned())
|
Ok(snapshot.relative_path().to_str().unwrap().to_owned())
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1764,8 +1764,9 @@ async fn complete_backup_snapshot_do(param: &HashMap<String, String>) -> Vec<Str
|
|||||||
if let (Some(backup_id), Some(backup_type), Some(backup_time)) =
|
if let (Some(backup_id), Some(backup_type), Some(backup_time)) =
|
||||||
(item["backup-id"].as_str(), item["backup-type"].as_str(), item["backup-time"].as_i64())
|
(item["backup-id"].as_str(), item["backup-type"].as_str(), item["backup-time"].as_i64())
|
||||||
{
|
{
|
||||||
let snapshot = BackupDir::new(backup_type, backup_id, backup_time);
|
if let Ok(snapshot) = BackupDir::new(backup_type, backup_id, backup_time) {
|
||||||
result.push(snapshot.relative_path().to_str().unwrap().to_owned());
|
result.push(snapshot.relative_path().to_str().unwrap().to_owned());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -347,7 +347,7 @@ pub async fn pull_group(
|
|||||||
let mut remote_snapshots = std::collections::HashSet::new();
|
let mut remote_snapshots = std::collections::HashSet::new();
|
||||||
|
|
||||||
for item in list {
|
for item in list {
|
||||||
let snapshot = BackupDir::new(item.backup_type, item.backup_id, item.backup_time);
|
let snapshot = BackupDir::new(item.backup_type, item.backup_id, item.backup_time)?;
|
||||||
|
|
||||||
// in-progress backups can't be synced
|
// in-progress backups can't be synced
|
||||||
if let None = item.size {
|
if let None = item.size {
|
||||||
|
Loading…
Reference in New Issue
Block a user