From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id D8B4461A90 for ; Tue, 15 Sep 2020 08:40:13 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id BDFE316C6B for ; Tue, 15 Sep 2020 08:40:13 +0200 (CEST) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [212.186.127.180]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS id DD20016C61 for ; Tue, 15 Sep 2020 08:40:08 +0200 (CEST) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id A167744BF2 for ; Tue, 15 Sep 2020 08:40:08 +0200 (CEST) Date: Tue, 15 Sep 2020 08:39:58 +0200 From: Fabian =?iso-8859-1?q?Gr=FCnbichler?= To: Proxmox VE development discussion References: <20200915053053.6918-1-dietmar@proxmox.com> In-Reply-To: <20200915053053.6918-1-dietmar@proxmox.com> MIME-Version: 1.0 User-Agent: astroid/0.15.0 (https://github.com/astroidmail/astroid) Message-Id: <1600149612.n0ad0vn01w.astroid@nora.none> Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-SPAM-LEVEL: Spam detection results: 0 AWL -0.224 Adjusted score from AWL reputation of From: address KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment KAM_NUMSUBJECT 0.5 Subject ends in numbers excluding current years RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [datastore.rs, status.rs, catalog.rs, ticket.rs, prune.rs, time.rs, key.rs, reader.rs, upid.rs, benchmark.rs, cache.rs, proxmox-backup-proxy.rs, self.group, rrd.rs, upload-speed.rs, manifest.rs, tools.rs, proxmox-backup-client.rs, jobstate.rs, format.rs] Subject: Re: [pve-devel] [PATCH proxmox-backup] avoid chrono dependency, depend on proxmox 0.3.8 X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 15 Sep 2020 06:40:13 -0000 some comments/nits inline, looks good to me otherwise. On September 15, 2020 7:30 am, Dietmar Maurer wrote: > - remove chrono dependency >=20 > - depend on proxmox 0.3.8 >=20 > - remove epoch_now, epoch_now_u64 and epoch_now_f64 >=20 > - remove tm_editor (moved to proxmox crate) >=20 > - use new helpers from proxmox 0.3.8 > * epoch_i64 and epoch_f64 > * parse_rfc3339 > * epoch_to_rfc3339_utc > * strftime_local >=20 > - BackupDir changes: > * store epoch and rfc3339 string instead of DateTime > * backup_time_to_string now return a Result > * remove unnecessary TryFrom<(BackupGroup, i64)> for BackupDir >=20 > - DynamicIndexHeader: change ctime to i64 >=20 > - FixedIndexHeader: change ctime to i64 > --- > Cargo.toml | 3 +- > examples/download-speed.rs | 4 +- > examples/upload-speed.rs | 2 +- > src/api2/admin/datastore.rs | 12 +-- > src/api2/node/rrd.rs | 3 +- > src/api2/node/time.rs | 10 +- > src/api2/reader.rs | 3 +- > src/api2/status.rs | 3 +- > src/auth_helpers.rs | 5 +- > src/backup/backup_info.rs | 77 +++++++------ > src/backup/catalog.rs | 9 +- > src/backup/crypt_config.rs | 5 +- > src/backup/datastore.rs | 3 +- > src/backup/dynamic_index.rs | 14 +-- > src/backup/fixed_index.rs | 29 +++-- > src/backup/key_derivation.rs | 17 ++- > src/backup/manifest.rs | 2 +- > src/backup/prune.rs | 61 +++++------ > src/bin/proxmox-backup-client.rs | 62 +++++------ > src/bin/proxmox-backup-proxy.rs | 41 +++---- > src/bin/proxmox_backup_client/benchmark.rs | 3 +- > src/bin/proxmox_backup_client/key.rs | 5 +- > src/client/backup_reader.rs | 5 +- > src/client/backup_writer.rs | 5 +- > src/client/http_client.rs | 5 +- > src/config/jobstate.rs | 5 +- > src/pxar/tools.rs | 8 +- > src/rrd/cache.rs | 3 +- > src/server/upid.rs | 3 +- > src/server/worker_task.rs | 10 +- > src/tools.rs | 14 --- > src/tools/file_logger.rs | 6 +- > src/tools/format.rs | 8 +- > src/tools/systemd.rs | 1 - > src/tools/systemd/time.rs | 5 +- > src/tools/systemd/tm_editor.rs | 119 --------------------- > src/tools/ticket.rs | 8 +- > 37 files changed, 198 insertions(+), 380 deletions(-) > delete mode 100644 src/tools/systemd/tm_editor.rs >=20 > diff --git a/Cargo.toml b/Cargo.toml > index 0625ffb..9d24242 100644 > --- a/Cargo.toml > +++ b/Cargo.toml > @@ -18,7 +18,6 @@ apt-pkg-native =3D "0.3.1" # custom patched version > base64 =3D "0.12" > bitflags =3D "1.2.1" > bytes =3D "0.5" > -chrono =3D "0.4" # Date and time library for Rust > crc32fast =3D "1" > endian_trait =3D { version =3D "0.6", features =3D ["arrays"] } > anyhow =3D "1.0" > @@ -39,7 +38,7 @@ pam-sys =3D "0.5" > percent-encoding =3D "2.1" > pin-utils =3D "0.1.0" > pathpatterns =3D "0.1.2" > -proxmox =3D { version =3D "0.3.5", features =3D [ "sortable-macro", "api= -macro", "websocket" ] } > +proxmox =3D { version =3D "0.3.8", features =3D [ "sortable-macro", "api= -macro", "websocket" ] } > #proxmox =3D { git =3D "ssh://gitolite3@proxdev.maurer-it.com/rust/proxm= ox", version =3D "0.1.2", features =3D [ "sortable-macro", "api-macro" ] } > #proxmox =3D { path =3D "../proxmox/proxmox", features =3D [ "sortable-m= acro", "api-macro", "websocket" ] } > proxmox-fuse =3D "0.1.0" > diff --git a/examples/download-speed.rs b/examples/download-speed.rs > index 694c55d..0ec6cb6 100644 > --- a/examples/download-speed.rs > +++ b/examples/download-speed.rs > @@ -2,8 +2,6 @@ use std::io::Write; > =20 > use anyhow::{Error}; > =20 > -use chrono::{DateTime, Utc}; > - > use proxmox_backup::api2::types::Userid; > use proxmox_backup::client::{HttpClient, HttpClientOptions, BackupReader= }; > =20 > @@ -36,7 +34,7 @@ async fn run() -> Result<(), Error> { > =20 > let client =3D HttpClient::new(host, username, options)?; > =20 > - let backup_time =3D "2019-06-28T10:49:48Z".parse::>()?= ; > + let backup_time =3D proxmox::tools::time::parse_rfc3339("2019-06-28T= 10:49:48Z")?; > =20 > let client =3D BackupReader::start(client, None, "store2", "host", "= elsa", backup_time, true) > .await?; > diff --git a/examples/upload-speed.rs b/examples/upload-speed.rs > index d67e9da..896e31e 100644 > --- a/examples/upload-speed.rs > +++ b/examples/upload-speed.rs > @@ -16,7 +16,7 @@ async fn upload_speed() -> Result { > =20 > let client =3D HttpClient::new(host, username, options)?; > =20 > - let backup_time =3D chrono::Utc::now(); > + let backup_time =3D proxmox::tools::time::epoch_i64(); > =20 > let client =3D BackupWriter::start(client, None, datastore, "host", = "speedtest", backup_time, false, true).await?; > =20 > diff --git a/src/api2/admin/datastore.rs b/src/api2/admin/datastore.rs > index be2796d..af3af0a 100644 > --- a/src/api2/admin/datastore.rs > +++ b/src/api2/admin/datastore.rs > @@ -172,7 +172,7 @@ fn list_groups( > let result_item =3D GroupListItem { > backup_type: group.backup_type().to_string(), > backup_id: group.backup_id().to_string(), > - last_backup: info.backup_dir.backup_time().timestamp(), > + last_backup: info.backup_dir.backup_time(), > backup_count: list.len() as u64, > files: info.files.clone(), > owner: Some(owner), > @@ -403,7 +403,7 @@ pub fn list_snapshots ( > let result_item =3D SnapshotListItem { > backup_type: group.backup_type().to_string(), > backup_id: group.backup_id().to_string(), > - backup_time: info.backup_dir.backup_time().timestamp(), > + backup_time: info.backup_dir.backup_time(), > comment, > verification, > files, > @@ -673,7 +673,7 @@ fn prune( > prune_result.push(json!({ > "backup-type": group.backup_type(), > "backup-id": group.backup_id(), > - "backup-time": backup_time.timestamp(), > + "backup-time": backup_time, > "keep": keep, > })); > } > @@ -697,7 +697,7 @@ fn prune( > if keep_all { keep =3D true; } > =20 > let backup_time =3D info.backup_dir.backup_time(); > - let timestamp =3D BackupDir::backup_time_to_string(backup_ti= me); > + let timestamp =3D info.backup_dir.backup_time_string(); > let group =3D info.backup_dir.group(); > =20 > =20 > @@ -714,7 +714,7 @@ fn prune( > prune_result.push(json!({ > "backup-type": group.backup_type(), > "backup-id": group.backup_id(), > - "backup-time": backup_time.timestamp(), > + "backup-time": backup_time, > "keep": keep, > })); > =20 > @@ -1097,7 +1097,7 @@ fn upload_backup_log( > } > =20 > println!("Upload backup log to {}/{}/{}/{}/{}", store, > - backup_type, backup_id, BackupDir::backup_time_to_strin= g(backup_dir.backup_time()), file_name); > + backup_type, backup_id, backup_dir.backup_time_string()= , file_name); > =20 > let data =3D req_body > .map_err(Error::from) > diff --git a/src/api2/node/rrd.rs b/src/api2/node/rrd.rs > index b857cd3..9988146 100644 > --- a/src/api2/node/rrd.rs > +++ b/src/api2/node/rrd.rs > @@ -4,7 +4,6 @@ use serde_json::{Value, json}; > use proxmox::api::{api, Router}; > =20 > use crate::api2::types::*; > -use crate::tools::epoch_now_f64; > use crate::rrd::{extract_cached_data, RRD_DATA_ENTRIES}; > =20 > pub fn create_value_from_rrd( > @@ -15,7 +14,7 @@ pub fn create_value_from_rrd( > ) -> Result { > =20 > let mut result =3D Vec::new(); > - let now =3D epoch_now_f64()?; > + let now =3D proxmox::tools::time::epoch_f64(); > =20 > for name in list { > let (start, reso, list) =3D match extract_cached_data(basedir, n= ame, now, timeframe, cf) { > diff --git a/src/api2/node/time.rs b/src/api2/node/time.rs > index a5afa40..3c8e6ab 100644 > --- a/src/api2/node/time.rs > +++ b/src/api2/node/time.rs > @@ -1,4 +1,3 @@ > -use chrono::prelude::*; > use anyhow::{bail, format_err, Error}; > use serde_json::{json, Value}; > =20 > @@ -57,10 +56,11 @@ fn read_etc_localtime() -> Result { > )] > /// Read server time and time zone settings. > fn get_time(_param: Value) -> Result { > - let datetime =3D Local::now(); > - let offset =3D datetime.offset(); > - let time =3D datetime.timestamp(); > - let localtime =3D time + (offset.fix().local_minus_utc() as i64); > + let time =3D proxmox::tools::time::epoch_i64(); > + let tm =3D proxmox::tools::time::localtime(time)?; > + let offset =3D tm.tm_gmtoff; > + > + let localtime =3D time + offset; > =20 > Ok(json!({ > "timezone": read_etc_localtime()?, > diff --git a/src/api2/reader.rs b/src/api2/reader.rs > index 5252d2e..0a72e34 100644 > --- a/src/api2/reader.rs > +++ b/src/api2/reader.rs > @@ -1,4 +1,3 @@ > -//use chrono::{Local, TimeZone}; > use anyhow::{bail, format_err, Error}; > use futures::*; > use hyper::header::{self, HeaderValue, UPGRADE}; > @@ -88,7 +87,7 @@ fn upgrade_to_backup_reader_protocol( > =20 > //let files =3D BackupInfo::list_files(&path, &backup_dir)?; > =20 > - let worker_id =3D format!("{}_{}_{}_{:08X}", store, backup_type,= backup_id, backup_dir.backup_time().timestamp()); > + let worker_id =3D format!("{}_{}_{}_{:08X}", store, backup_type,= backup_id, backup_dir.backup_time()); > =20 > WorkerTask::spawn("reader", Some(worker_id), userid.clone(), tru= e, move |worker| { > let mut env =3D ReaderEnvironment::new( > diff --git a/src/api2/status.rs b/src/api2/status.rs > index 10ae8b3..eb8c43c 100644 > --- a/src/api2/status.rs > +++ b/src/api2/status.rs > @@ -23,7 +23,6 @@ use crate::api2::types::{ > use crate::server; > use crate::backup::{DataStore}; > use crate::config::datastore; > -use crate::tools::epoch_now_f64; > use crate::tools::statistics::{linear_regression}; > use crate::config::cached_user_info::CachedUserInfo; > use crate::config::acl::{ > @@ -110,7 +109,7 @@ fn datastore_status( > }); > =20 > let rrd_dir =3D format!("datastore/{}", store); > - let now =3D epoch_now_f64()?; > + let now =3D proxmox::tools::time::epoch_f64(); > let rrd_resolution =3D RRDTimeFrameResolution::Month; > let rrd_mode =3D RRDMode::Average; > =20 > diff --git a/src/auth_helpers.rs b/src/auth_helpers.rs > index 54c5d4d..fca9015 100644 > --- a/src/auth_helpers.rs > +++ b/src/auth_helpers.rs > @@ -11,7 +11,6 @@ use proxmox::tools::fs::{file_get_contents, replace_fil= e, CreateOptions}; > use proxmox::try_block; > =20 > use crate::api2::types::Userid; > -use crate::tools::epoch_now_u64; > =20 > fn compute_csrf_secret_digest( > timestamp: i64, > @@ -32,7 +31,7 @@ pub fn assemble_csrf_prevention_token( > userid: &Userid, > ) -> String { > =20 > - let epoch =3D epoch_now_u64().unwrap() as i64; > + let epoch =3D proxmox::tools::time::epoch_i64(); > =20 > let digest =3D compute_csrf_secret_digest(epoch, secret, userid); > =20 > @@ -69,7 +68,7 @@ pub fn verify_csrf_prevention_token( > bail!("invalid signature."); > } > =20 > - let now =3D epoch_now_u64()? as i64; > + let now =3D proxmox::tools::time::epoch_i64(); > =20 > let age =3D now - ttime; > if age < min_age { > diff --git a/src/backup/backup_info.rs b/src/backup/backup_info.rs > index 023625f..ddc0eb8 100644 > --- a/src/backup/backup_info.rs > +++ b/src/backup/backup_info.rs > @@ -2,11 +2,8 @@ use crate::tools; > =20 > use anyhow::{bail, format_err, Error}; > use regex::Regex; > -use std::convert::TryFrom; > use std::os::unix::io::RawFd; > =20 > -use chrono::{DateTime, LocalResult, TimeZone, SecondsFormat, Utc}; > - > use std::path::{PathBuf, Path}; > use lazy_static::lazy_static; > =20 > @@ -106,8 +103,8 @@ impl BackupGroup { > tools::scandir(libc::AT_FDCWD, &path, &BACKUP_DATE_REGEX, |l2_fd= , backup_time, file_type| { > if file_type !=3D nix::dir::Type::Directory { return Ok(());= } > =20 > - let dt =3D backup_time.parse::>()?; > - let backup_dir =3D BackupDir::new(self.backup_type.clone(), = self.backup_id.clone(), dt.timestamp())?; > + let timestamp =3D proxmox::tools::time::parse_rfc3339(backup= _time)?; > + let backup_dir =3D BackupDir::new(self.backup_type.clone(), = self.backup_id.clone(), timestamp)?; > let files =3D list_backup_files(l2_fd, backup_time)?; this maps backup_type, _id &str's and RFC3339 backup_time to a new=20 BackupDir and lists its files > =20 > list.push(BackupInfo { backup_dir, files }); > @@ -117,7 +114,7 @@ impl BackupGroup { > Ok(list) > } > =20 > - pub fn last_successful_backup(&self, base_path: &Path) -> Result>, Error> { > + pub fn last_successful_backup(&self, base_path: &Path) -> Result, Error> { > =20 > let mut last =3D None; > =20 > @@ -143,11 +140,11 @@ impl BackupGroup { > } > } > =20 > - let dt =3D backup_time.parse::>()?; > - if let Some(last_dt) =3D last { > - if dt > last_dt { last =3D Some(dt); } > + let timestamp =3D proxmox::tools::time::parse_rfc3339(backup= _time)?; > + if let Some(last_timestamp) =3D last { > + if timestamp > last_timestamp { last =3D Some(timestamp)= ; } > } else { > - last =3D Some(dt); > + last =3D Some(timestamp); > } > =20 > Ok(()) > @@ -204,48 +201,51 @@ pub struct BackupDir { > /// Backup group > group: BackupGroup, > /// Backup timestamp > - backup_time: DateTime, > + backup_time: i64, > + // backup_time as rfc3339 > + backup_time_string: String > } > =20 > impl BackupDir { > =20 > - pub fn new(backup_type: T, backup_id: U, timestamp: i64) -> Re= sult > + pub fn new(backup_type: T, backup_id: U, backup_time: i64) -> = Result > where > T: Into, > U: Into, > { > let group =3D BackupGroup::new(backup_type.into(), backup_id.int= o()); > - BackupDir::new_with_group(group, timestamp) > + BackupDir::new_with_group(group, backup_time) > } > =20 > - pub fn new_with_group(group: BackupGroup, timestamp: i64) -> Result<= Self, Error> { > - let backup_time =3D match Utc.timestamp_opt(timestamp, 0) { > - LocalResult::Single(time) =3D> time, > - _ =3D> bail!("can't create BackupDir with invalid backup tim= e {}", timestamp), > - }; > - > - Ok(Self { group, backup_time }) > + pub fn new_with_group(group: BackupGroup, backup_time: i64) -> Resul= t { > + let backup_time_string =3D Self::backup_time_to_string(backup_ti= me)?; > + Ok(Self { group, backup_time, backup_time_string }) > } > =20 > pub fn group(&self) -> &BackupGroup { > &self.group > } > =20 > - pub fn backup_time(&self) -> DateTime { > + pub fn backup_time(&self) -> i64 { > self.backup_time > } > =20 > + pub fn backup_time_string(&self) -> &str { > + &self.backup_time_string > + } > + > pub fn relative_path(&self) -> PathBuf { > =20 > let mut relative_path =3D self.group.group_path(); > =20 > - relative_path.push(Self::backup_time_to_string(self.backup_time)= ); > + relative_path.push(self.backup_time_string.clone()); > =20 > relative_path > } > =20 > - pub fn backup_time_to_string(backup_time: DateTime) -> String { > - backup_time.to_rfc3339_opts(SecondsFormat::Secs, true) > + pub fn backup_time_to_string(backup_time: i64) -> Result { > + // fixme: can this fail? (avoid unwrap) > + proxmox::tools::time::epoch_to_rfc3339_utc(backup_time) > } > } > =20 > @@ -260,8 +260,9 @@ impl std::str::FromStr for BackupDir { > .ok_or_else(|| format_err!("unable to parse backup snapshot = path '{}'", path))?; > =20 > let group =3D BackupGroup::new(cap.get(1).unwrap().as_str(), cap= .get(2).unwrap().as_str()); > - let backup_time =3D cap.get(3).unwrap().as_str().parse::>()?; > - BackupDir::try_from((group, backup_time.timestamp())) > + let backup_time_string =3D cap.get(3).unwrap().as_str().to_owned= (); > + let backup_time =3D proxmox::tools::time::parse_rfc3339(&backup_= time_string)?; > + Ok(BackupDir { group, backup_time, backup_time_string }) this creates a new BackupDir from backup_type &str, backup_id &str and=20 RFC3339 backup_time (via creating a group, which is not re-used) > } > } > =20 > @@ -269,16 +270,7 @@ impl std::fmt::Display for BackupDir { > fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { > let backup_type =3D self.group.backup_type(); > let id =3D self.group.backup_id(); > - let time =3D Self::backup_time_to_string(self.backup_time); > - write!(f, "{}/{}/{}", backup_type, id, time) > - } > -} > - > -impl TryFrom<(BackupGroup, i64)> for BackupDir { > - type Error =3D Error; > - > - fn try_from((group, timestamp): (BackupGroup, i64)) -> Result { > - BackupDir::new_with_group(group, timestamp) > + write!(f, "{}/{}/{}", backup_type, id, self.backup_time_string) > } > } > =20 > @@ -336,13 +328,18 @@ impl BackupInfo { > if file_type !=3D nix::dir::Type::Directory { return Ok(());= } > tools::scandir(l0_fd, backup_type, &BACKUP_ID_REGEX, |l1_fd,= backup_id, file_type| { > if file_type !=3D nix::dir::Type::Directory { return Ok(= ()); } > - tools::scandir(l1_fd, backup_id, &BACKUP_DATE_REGEX, |l2= _fd, backup_time, file_type| { > + tools::scandir(l1_fd, backup_id, &BACKUP_DATE_REGEX, |l2= _fd, backup_time_string, file_type| { > if file_type !=3D nix::dir::Type::Directory { return= Ok(()); } > =20 > - let dt =3D backup_time.parse::>()?; > - let backup_dir =3D BackupDir::new(backup_type, backu= p_id, dt.timestamp())?; > + let backup_time =3D proxmox::tools::time::parse_rfc3= 339(backup_time_string)?; > + > + let backup_dir =3D BackupDir { > + group: BackupGroup::new(backup_type, backup_id), > + backup_time, > + backup_time_string: backup_time_string.to_owned(= ), > + }; > =20 > - let files =3D list_backup_files(l2_fd, backup_time)?= ; > + let files =3D list_backup_files(l2_fd, backup_time_s= tring)?; this creates a new BackupDir from backup_type, backup_id and RFC3339=20 backup_time and lists its backup snapshots. maybe we want a constructor that allows us to do let backup_dir: BackupDir =3D (backup_type, backup_id, backup_time_rfc3339)= ; to cut down the redundancy here.. > =20 > list.push(BackupInfo { backup_dir, files }); > =20 > diff --git a/src/backup/catalog.rs b/src/backup/catalog.rs > index 85a3262..d1f519e 100644 > --- a/src/backup/catalog.rs > +++ b/src/backup/catalog.rs > @@ -5,7 +5,6 @@ use std::io::{Read, Write, Seek, SeekFrom}; > use std::os::unix::ffi::OsStrExt; > =20 > use anyhow::{bail, format_err, Error}; > -use chrono::offset::{TimeZone, Local, LocalResult}; > =20 > use pathpatterns::{MatchList, MatchType}; > use proxmox::tools::io::ReadExt; > @@ -533,10 +532,10 @@ impl CatalogReader { > self.dump_dir(&path, pos)?; > } > CatalogEntryType::File =3D> { > - let mtime_string =3D match Local.timestamp_opt(mtime= as i64, 0) { > - LocalResult::Single(time) =3D> time.to_rfc3339_o= pts(chrono::SecondsFormat::Secs, false), > - _ =3D> (mtime as i64).to_string(), > - }; > + let mut mtime_string =3D mtime.to_string(); > + if let Ok(s) =3D proxmox::tools::time::strftime_loca= l("%FT%TZ", mtime as i64) { > + mtime_string =3D s; > + } > =20 > println!( > "{} {:?} {} {}", > diff --git a/src/backup/crypt_config.rs b/src/backup/crypt_config.rs > index c30fb5f..4be728d 100644 > --- a/src/backup/crypt_config.rs > +++ b/src/backup/crypt_config.rs > @@ -10,7 +10,6 @@ > use std::io::Write; > =20 > use anyhow::{bail, Error}; > -use chrono::{Local, DateTime}; > use openssl::hash::MessageDigest; > use openssl::pkcs5::pbkdf2_hmac; > use openssl::symm::{decrypt_aead, Cipher, Crypter, Mode}; > @@ -216,10 +215,10 @@ impl CryptConfig { > pub fn generate_rsa_encoded_key( > &self, > rsa: openssl::rsa::Rsa, > - created: DateTime, > + created: i64, > ) -> Result, Error> { > =20 > - let modified =3D Local::now(); > + let modified =3D proxmox::tools::time::epoch_i64(); > let key_config =3D super::KeyConfig { kdf: None, created, modifi= ed, data: self.enc_key.to_vec() }; > let data =3D serde_json::to_string(&key_config)?.as_bytes().to_v= ec(); > =20 > diff --git a/src/backup/datastore.rs b/src/backup/datastore.rs > index ebe4748..46a5069 100644 > --- a/src/backup/datastore.rs > +++ b/src/backup/datastore.rs > @@ -6,7 +6,6 @@ use std::convert::TryFrom; > =20 > use anyhow::{bail, format_err, Error}; > use lazy_static::lazy_static; > -use chrono::{DateTime, Utc}; > use serde_json::Value; > =20 > use proxmox::tools::fs::{replace_file, CreateOptions}; > @@ -242,7 +241,7 @@ impl DataStore { > /// Returns the time of the last successful backup > /// > /// Or None if there is no backup in the group (or the group dir doe= s not exist). > - pub fn last_successful_backup(&self, backup_group: &BackupGroup) -> = Result>, Error> { > + pub fn last_successful_backup(&self, backup_group: &BackupGroup) -> = Result, Error> { > let base_path =3D self.base_path(); > let mut group_path =3D base_path.clone(); > group_path.push(backup_group.group_path()); > diff --git a/src/backup/dynamic_index.rs b/src/backup/dynamic_index.rs > index f70aa44..1cc4e53 100644 > --- a/src/backup/dynamic_index.rs > +++ b/src/backup/dynamic_index.rs > @@ -21,14 +21,14 @@ use super::read_chunk::ReadChunk; > use super::Chunker; > use super::IndexFile; > use super::{DataBlob, DataChunkBuilder}; > -use crate::tools::{self, epoch_now_u64}; > +use crate::tools; > =20 > /// Header format definition for dynamic index files (`.dixd`) > #[repr(C)] > pub struct DynamicIndexHeader { > pub magic: [u8; 8], > pub uuid: [u8; 16], > - pub ctime: u64, > + pub ctime: i64, > /// Sha256 over the index ``SHA256(offset1||digest1||offset2||digest= 2||...)`` > pub index_csum: [u8; 32], > reserved: [u8; 4032], // overall size is one page (4096 bytes) > @@ -77,7 +77,7 @@ pub struct DynamicIndexReader { > pub size: usize, > index: Mmap, > pub uuid: [u8; 16], > - pub ctime: u64, > + pub ctime: i64, > pub index_csum: [u8; 32], > } > =20 > @@ -107,7 +107,7 @@ impl DynamicIndexReader { > bail!("got unknown magic number"); > } > =20 > - let ctime =3D u64::from_le(header.ctime); > + let ctime =3D proxmox::tools::time::epoch_i64(); > =20 > let rawfd =3D file.as_raw_fd(); > =20 > @@ -480,7 +480,7 @@ pub struct DynamicIndexWriter { > tmp_filename: PathBuf, > csum: Option, > pub uuid: [u8; 16], > - pub ctime: u64, > + pub ctime: i64, > } > =20 > impl Drop for DynamicIndexWriter { > @@ -506,13 +506,13 @@ impl DynamicIndexWriter { > =20 > let mut writer =3D BufWriter::with_capacity(1024 * 1024, file); > =20 > - let ctime =3D epoch_now_u64()?; > + let ctime =3D proxmox::tools::time::epoch_i64(); > =20 > let uuid =3D Uuid::generate(); > =20 > let mut header =3D DynamicIndexHeader::zeroed(); > header.magic =3D super::DYNAMIC_SIZED_CHUNK_INDEX_1_0; > - header.ctime =3D u64::to_le(ctime); > + header.ctime =3D i64::to_le(ctime); > header.uuid =3D *uuid.as_bytes(); > // header.index_csum =3D [0u8; 32]; > writer.write_all(header.as_bytes())?; > diff --git a/src/backup/fixed_index.rs b/src/backup/fixed_index.rs > index 309f450..a2317f0 100644 > --- a/src/backup/fixed_index.rs > +++ b/src/backup/fixed_index.rs > @@ -4,9 +4,8 @@ use std::io::{Seek, SeekFrom}; > use super::chunk_stat::*; > use super::chunk_store::*; > use super::{IndexFile, ChunkReadInfo}; > -use crate::tools::{self, epoch_now_u64}; > +use crate::tools; > =20 > -use chrono::{Local, LocalResult, TimeZone}; > use std::fs::File; > use std::io::Write; > use std::os::unix::io::AsRawFd; > @@ -23,7 +22,7 @@ use proxmox::tools::Uuid; > pub struct FixedIndexHeader { > pub magic: [u8; 8], > pub uuid: [u8; 16], > - pub ctime: u64, > + pub ctime: i64, > /// Sha256 over the index ``SHA256(digest1||digest2||...)`` > pub index_csum: [u8; 32], > pub size: u64, > @@ -41,7 +40,7 @@ pub struct FixedIndexReader { > index_length: usize, > index: *mut u8, > pub uuid: [u8; 16], > - pub ctime: u64, > + pub ctime: i64, > pub index_csum: [u8; 32], > } > =20 > @@ -82,7 +81,7 @@ impl FixedIndexReader { > } > =20 > let size =3D u64::from_le(header.size); > - let ctime =3D u64::from_le(header.ctime); > + let ctime =3D i64::from_le(header.ctime); > let chunk_size =3D u64::from_le(header.chunk_size); > =20 > let index_length =3D ((size + chunk_size - 1) / chunk_size) as u= size; > @@ -148,13 +147,13 @@ impl FixedIndexReader { > pub fn print_info(&self) { > println!("Size: {}", self.size); > println!("ChunkSize: {}", self.chunk_size); > - println!( > - "CTime: {}", > - match Local.timestamp_opt(self.ctime as i64, 0) { > - LocalResult::Single(ctime) =3D> ctime.format("%c").to_st= ring(), > - _ =3D> (self.ctime as i64).to_string(), > - } > - ); > + > + let mut ctime_str =3D self.ctime.to_string(); > + if let Ok(s) =3D proxmox::tools::time::strftime_local("%c",self.= ctime) { > + ctime_str =3D s; > + } > + > + println!("CTime: {}", ctime_str); > println!("UUID: {:?}", self.uuid); > } > } > @@ -231,7 +230,7 @@ pub struct FixedIndexWriter { > index_length: usize, > index: *mut u8, > pub uuid: [u8; 16], > - pub ctime: u64, > + pub ctime: i64, > } > =20 > // `index` is mmap()ed which cannot be thread-local so should be sendabl= e > @@ -274,7 +273,7 @@ impl FixedIndexWriter { > panic!("got unexpected header size"); > } > =20 > - let ctime =3D epoch_now_u64()?; > + let ctime =3D proxmox::tools::time::epoch_i64(); > =20 > let uuid =3D Uuid::generate(); > =20 > @@ -282,7 +281,7 @@ impl FixedIndexWriter { > let header =3D unsafe { &mut *(buffer.as_ptr() as *mut FixedInde= xHeader) }; > =20 > header.magic =3D super::FIXED_SIZED_CHUNK_INDEX_1_0; > - header.ctime =3D u64::to_le(ctime); > + header.ctime =3D i64::to_le(ctime); > header.size =3D u64::to_le(size as u64); > header.chunk_size =3D u64::to_le(chunk_size as u64); > header.uuid =3D *uuid.as_bytes(); > diff --git a/src/backup/key_derivation.rs b/src/backup/key_derivation.rs > index ac27da6..2c80772 100644 > --- a/src/backup/key_derivation.rs > +++ b/src/backup/key_derivation.rs > @@ -1,7 +1,6 @@ > use anyhow::{bail, format_err, Context, Error}; > =20 > use serde::{Deserialize, Serialize}; > -use chrono::{Local, DateTime}; > =20 > use proxmox::tools::fs::{file_get_contents, replace_file, CreateOptions}= ; > use proxmox::try_block; > @@ -61,10 +60,10 @@ impl KeyDerivationConfig { > #[derive(Deserialize, Serialize, Debug)] > pub struct KeyConfig { > pub kdf: Option, > - #[serde(with =3D "proxmox::tools::serde::date_time_as_rfc3339")] > - pub created: DateTime, > - #[serde(with =3D "proxmox::tools::serde::date_time_as_rfc3339")] > - pub modified: DateTime, > + #[serde(with =3D "proxmox::tools::serde::epoch_as_rfc3339")] > + pub created: i64, > + #[serde(with =3D "proxmox::tools::serde::epoch_as_rfc3339")] > + pub modified: i64, > #[serde(with =3D "proxmox::tools::serde::bytes_as_base64")] > pub data: Vec, > } > @@ -136,7 +135,7 @@ pub fn encrypt_key_with_passphrase( > enc_data.extend_from_slice(&tag); > enc_data.extend_from_slice(&encrypted_key); > =20 > - let created =3D Local::now(); > + let created =3D proxmox::tools::time::epoch_i64(); > =20 > Ok(KeyConfig { > kdf: Some(kdf), > @@ -149,7 +148,7 @@ pub fn encrypt_key_with_passphrase( > pub fn load_and_decrypt_key( > path: &std::path::Path, > passphrase: &dyn Fn() -> Result, Error>, > -) -> Result<([u8;32], DateTime), Error> { > +) -> Result<([u8;32], i64), Error> { > do_load_and_decrypt_key(path, passphrase) > .with_context(|| format!("failed to load decryption key from {:?= }", path)) > } > @@ -157,14 +156,14 @@ pub fn load_and_decrypt_key( > fn do_load_and_decrypt_key( > path: &std::path::Path, > passphrase: &dyn Fn() -> Result, Error>, > -) -> Result<([u8;32], DateTime), Error> { > +) -> Result<([u8;32], i64), Error> { > decrypt_key(&file_get_contents(&path)?, passphrase) > } > =20 > pub fn decrypt_key( > mut keydata: &[u8], > passphrase: &dyn Fn() -> Result, Error>, > -) -> Result<([u8;32], DateTime), Error> { > +) -> Result<([u8;32], i64), Error> { > let key_config: KeyConfig =3D serde_json::from_reader(&mut keydata)?= ; > =20 > let raw_data =3D key_config.data; > diff --git a/src/backup/manifest.rs b/src/backup/manifest.rs > index ed5e2a2..609cc99 100644 > --- a/src/backup/manifest.rs > +++ b/src/backup/manifest.rs > @@ -103,7 +103,7 @@ impl BackupManifest { > Self { > backup_type: snapshot.group().backup_type().into(), > backup_id: snapshot.group().backup_id().into(), > - backup_time: snapshot.backup_time().timestamp(), > + backup_time: snapshot.backup_time(), > files: Vec::new(), > unprotected: json!({}), > signature: None, > diff --git a/src/backup/prune.rs b/src/backup/prune.rs > index f7a87c5..bc0a75a 100644 > --- a/src/backup/prune.rs > +++ b/src/backup/prune.rs > @@ -2,18 +2,16 @@ use anyhow::{Error}; > use std::collections::{HashMap, HashSet}; > use std::path::PathBuf; > =20 > -use chrono::{DateTime, Timelike, Datelike, Local}; > - > -use super::{BackupDir, BackupInfo}; > +use super::BackupInfo; > =20 > enum PruneMark { Keep, KeepPartial, Remove } > =20 > -fn mark_selections, &BackupInfo) -> String> ( > +fn mark_selections Result> ( > mark: &mut HashMap, > list: &Vec, > keep: usize, > select_id: F, > -) { > +) -> Result<(), Error> { > =20 > let mut include_hash =3D HashSet::new(); > =20 > @@ -21,8 +19,7 @@ fn mark_selections, &BackupInfo) = -> String> ( > for info in list { > let backup_id =3D info.backup_dir.relative_path(); > if let Some(PruneMark::Keep) =3D mark.get(&backup_id) { > - let local_time =3D info.backup_dir.backup_time().with_timezo= ne(&Local); > - let sel_id: String =3D select_id(local_time, &info); > + let sel_id: String =3D select_id(&info)?; > already_included.insert(sel_id); > } > } > @@ -30,8 +27,7 @@ fn mark_selections, &BackupInfo) = -> String> ( > for info in list { > let backup_id =3D info.backup_dir.relative_path(); > if let Some(_) =3D mark.get(&backup_id) { continue; } > - let local_time =3D info.backup_dir.backup_time().with_timezone(&= Local); > - let sel_id: String =3D select_id(local_time, &info); > + let sel_id: String =3D select_id(&info)?; > =20 > if already_included.contains(&sel_id) { continue; } > =20 > @@ -43,6 +39,8 @@ fn mark_selections, &BackupInfo) = -> String> ( > mark.insert(backup_id, PruneMark::Remove); > } > } > + > + Ok(()) > } > =20 > fn remove_incomplete_snapshots( > @@ -182,44 +180,43 @@ pub fn compute_prune_info( > remove_incomplete_snapshots(&mut mark, &list); > =20 > if let Some(keep_last) =3D options.keep_last { > - mark_selections(&mut mark, &list, keep_last as usize, |_local_ti= me, info| { > - BackupDir::backup_time_to_string(info.backup_dir.backup_time= ()) > - }); > + mark_selections(&mut mark, &list, keep_last as usize, |info| { > + Ok(info.backup_dir.backup_time_string().to_owned()) > + })?; > } > =20 > + use proxmox::tools::time::strftime_local; > + > if let Some(keep_hourly) =3D options.keep_hourly { > - mark_selections(&mut mark, &list, keep_hourly as usize, |local_t= ime, _info| { > - format!("{}/{}/{}/{}", local_time.year(), local_time.month()= , > - local_time.day(), local_time.hour()) > - }); > + mark_selections(&mut mark, &list, keep_hourly as usize, |info| { > + strftime_local("%Y/%m/%d/%H", info.backup_dir.backup_time()) > + })?; > } > =20 > if let Some(keep_daily) =3D options.keep_daily { > - mark_selections(&mut mark, &list, keep_daily as usize, |local_ti= me, _info| { > - format!("{}/{}/{}", local_time.year(), local_time.month(), l= ocal_time.day()) > - }); > + mark_selections(&mut mark, &list, keep_daily as usize, |info| { > + strftime_local("%Y/%m/%d", info.backup_dir.backup_time()) > + })?; > } > =20 > if let Some(keep_weekly) =3D options.keep_weekly { > - mark_selections(&mut mark, &list, keep_weekly as usize, |local_t= ime, _info| { > - let iso_week =3D local_time.iso_week(); > - let week =3D iso_week.week(); > - // Note: This year number might not match the calendar year = number. > - let iso_week_year =3D iso_week.year(); > - format!("{}/{}", iso_week_year, week) > - }); > + mark_selections(&mut mark, &list, keep_weekly as usize, |info| { > + // Note: Use iso-week year/week here. This year number > + // might not match the calendar year number. > + strftime_local("%G/%V", info.backup_dir.backup_time()) > + })?; > } > =20 > if let Some(keep_monthly) =3D options.keep_monthly { > - mark_selections(&mut mark, &list, keep_monthly as usize, |local_= time, _info| { > - format!("{}/{}", local_time.year(), local_time.month()) > - }); > + mark_selections(&mut mark, &list, keep_monthly as usize, |info| = { > + strftime_local("%Y/%m", info.backup_dir.backup_time()) > + })?; > } > =20 > if let Some(keep_yearly) =3D options.keep_yearly { > - mark_selections(&mut mark, &list, keep_yearly as usize, |local_t= ime, _info| { > - format!("{}/{}", local_time.year(), local_time.year()) > - }); > + mark_selections(&mut mark, &list, keep_yearly as usize, |info| { > + strftime_local("%Y", info.backup_dir.backup_time()) > + })?; > } > =20 > let prune_info: Vec<(BackupInfo, bool)> =3D list.into_iter() > diff --git a/src/bin/proxmox-backup-client.rs b/src/bin/proxmox-backup-cl= ient.rs > index fa13203..c0cd86a 100644 > --- a/src/bin/proxmox-backup-client.rs > +++ b/src/bin/proxmox-backup-client.rs > @@ -8,7 +8,6 @@ use std::sync::{Arc, Mutex}; > use std::task::Context; > =20 > use anyhow::{bail, format_err, Error}; > -use chrono::{Local, LocalResult, DateTime, Utc, TimeZone}; > use futures::future::FutureExt; > use futures::stream::{StreamExt, TryStreamExt}; > use serde_json::{json, Value}; > @@ -16,11 +15,20 @@ use tokio::sync::mpsc; > use xdg::BaseDirectories; > =20 > use pathpatterns::{MatchEntry, MatchType, PatternFlag}; > -use proxmox::tools::fs::{file_get_contents, file_get_json, replace_file,= CreateOptions, image_size}; > -use proxmox::api::{ApiHandler, ApiMethod, RpcEnvironment}; > -use proxmox::api::schema::*; > -use proxmox::api::cli::*; > -use proxmox::api::api; > +use proxmox::{ > + tools::{ > + time::{strftime_local, epoch_i64}, > + fs::{file_get_contents, file_get_json, replace_file, CreateOptio= ns, image_size}, > + }, > + api::{ > + api, > + ApiHandler, > + ApiMethod, > + RpcEnvironment, > + schema::*, > + cli::*, > + }, > +}; > use pxar::accessor::{MaybeReady, ReadAt, ReadAtOperation}; > =20 > use proxmox_backup::tools; > @@ -246,7 +254,7 @@ pub async fn api_datastore_latest_snapshot( > client: &HttpClient, > store: &str, > group: BackupGroup, > -) -> Result<(String, String, DateTime), Error> { > +) -> Result<(String, String, i64), Error> { > =20 > let list =3D api_datastore_list_snapshots(client, store, Some(group.= clone())).await?; > let mut list: Vec =3D serde_json::from_value(list)= ?; > @@ -257,11 +265,7 @@ pub async fn api_datastore_latest_snapshot( > =20 > list.sort_unstable_by(|a, b| b.backup_time.cmp(&a.backup_time)); > =20 > - let backup_time =3D match Utc.timestamp_opt(list[0].backup_time, 0) = { > - LocalResult::Single(time) =3D> time, > - _ =3D> bail!("last snapshot of backup group {:?} has invalid tim= estmap {}.", > - group.group_path(), list[0].backup_time), > - }; > + let backup_time =3D list[0].backup_time; > =20 > Ok((group.backup_type().to_owned(), group.backup_id().to_owned(), ba= ckup_time)) > } > @@ -506,7 +510,7 @@ async fn forget_snapshots(param: Value) -> Result { > let result =3D client.delete(&path, Some(json!({ > "backup-type": snapshot.group().backup_type(), > "backup-id": snapshot.group().backup_id(), > - "backup-time": snapshot.backup_time().timestamp(), > + "backup-time": snapshot.backup_time(), > }))).await?; > =20 > record_repository(&repo); > @@ -643,7 +647,7 @@ async fn list_snapshot_files(param: Value) -> Result<= Value, Error> { > let mut result =3D client.get(&path, Some(json!({ > "backup-type": snapshot.group().backup_type(), > "backup-id": snapshot.group().backup_id(), > - "backup-time": snapshot.backup_time().timestamp(), > + "backup-time": snapshot.backup_time(), > }))).await?; > =20 > record_repository(&repo); > @@ -990,26 +994,18 @@ async fn create_backup( > } > } > =20 > - let backup_time =3D match backup_time_opt { > - Some(timestamp) =3D> { > - match Utc.timestamp_opt(timestamp, 0) { > - LocalResult::Single(time) =3D> time, > - _ =3D> bail!("Invalid backup-time parameter: {}", timest= amp), > - } > - }, > - _ =3D> Utc::now(), > - }; > + let backup_time =3D backup_time_opt.unwrap_or_else(|| epoch_i64()); > =20 > let client =3D connect(repo.host(), repo.user())?; > record_repository(&repo); > =20 > - println!("Starting backup: {}/{}/{}", backup_type, backup_id, Backup= Dir::backup_time_to_string(backup_time)); > + println!("Starting backup: {}/{}/{}", backup_type, backup_id, Backup= Dir::backup_time_to_string(backup_time)?); > =20 > println!("Client name: {}", proxmox::tools::nodename()); > =20 > - let start_time =3D Local::now(); > + let start_time =3D std::time::Instant::now(); > =20 > - println!("Starting protocol: {}", start_time.to_rfc3339_opts(chrono:= :SecondsFormat::Secs, false)); > + println!("Starting backup protocol: {}", strftime_local("%c", epoch_= i64())?); > =20 > let (crypt_config, rsa_encrypted_key) =3D match keydata { > None =3D> (None, None), > @@ -1047,7 +1043,7 @@ async fn create_backup( > None > }; > =20 > - let snapshot =3D BackupDir::new(backup_type, backup_id, backup_time.= timestamp())?; > + let snapshot =3D BackupDir::new(backup_type, backup_id, backup_time)= ?; > let mut manifest =3D BackupManifest::new(snapshot); > =20 > let mut catalog =3D None; > @@ -1162,11 +1158,11 @@ async fn create_backup( > =20 > client.finish().await?; > =20 > - let end_time =3D Local::now(); > - let elapsed =3D end_time.signed_duration_since(start_time); > - println!("Duration: {}", elapsed); > + let end_time =3D std::time::Instant::now(); > + let elapsed =3D end_time.duration_since(start_time); > + println!("Duration: {:.2}s", elapsed.as_secs_f64()); > =20 > - println!("End Time: {}", end_time.to_rfc3339_opts(chrono::SecondsFor= mat::Secs, false)); > + println!("End Time: {}", strftime_local("%c", epoch_i64())?); > =20 > Ok(Value::Null) > } > @@ -1504,7 +1500,7 @@ async fn upload_log(param: Value) -> Result { > let args =3D json!({ > "backup-type": snapshot.group().backup_type(), > "backup-id": snapshot.group().backup_id(), > - "backup-time": snapshot.backup_time().timestamp(), > + "backup-time": snapshot.backup_time(), > }); > =20 > let body =3D hyper::Body::from(raw_data); > @@ -1800,7 +1796,7 @@ async fn complete_server_file_name_do(param: &HashM= ap) -> Vec let query =3D tools::json_object_to_query(json!({ > "backup-type": snapshot.group().backup_type(), > "backup-id": snapshot.group().backup_id(), > - "backup-time": snapshot.backup_time().timestamp(), > + "backup-time": snapshot.backup_time(), > })).unwrap(); > =20 > let path =3D format!("api2/json/admin/datastore/{}/files?{}", repo.s= tore(), query); > diff --git a/src/bin/proxmox-backup-proxy.rs b/src/bin/proxmox-backup-pro= xy.rs > index 5844e63..4e49615 100644 > --- a/src/bin/proxmox-backup-proxy.rs > +++ b/src/bin/proxmox-backup-proxy.rs > @@ -13,7 +13,7 @@ use proxmox_backup::api2::types::Userid; > use proxmox_backup::configdir; > use proxmox_backup::buildcfg; > use proxmox_backup::server; > -use proxmox_backup::tools::{daemon, epoch_now, epoch_now_u64}; > +use proxmox_backup::tools::daemon; > use proxmox_backup::server::{ApiConfig, rest::*}; > use proxmox_backup::auth_helpers::*; > use proxmox_backup::tools::disks::{ DiskManage, zfs_pool_stats }; > @@ -144,11 +144,12 @@ fn start_task_scheduler() { > tokio::spawn(task.map(|_| ())); > } > =20 > -use std::time:: {Instant, Duration}; > +use std::time::{SystemTime, Instant, Duration, UNIX_EPOCH}; > =20 > fn next_minute() -> Result { > - let epoch_now =3D epoch_now()?; > - let epoch_next =3D Duration::from_secs((epoch_now.as_secs()/60 + 1)*= 60); > + let now =3D SystemTime::now(); > + let epoch_now =3D now.duration_since(UNIX_EPOCH)?; > + let epoch_next =3D Duration::from_secs((epoch_now.as_secs()/60 + 1)= *60); > Ok(Instant::now() + epoch_next - epoch_now) this looks weird.. wouldn't Ok(Instant::now() + Duration::from_secs(60)) serve the same purpose, since epoch_now and epoch_next are always 60s=20 apart? > } > =20 > @@ -308,13 +309,8 @@ async fn schedule_datastore_garbage_collection() { > } > }; > =20 > - let now =3D match epoch_now_u64() { > - Ok(epoch_now) =3D> epoch_now as i64, > - Err(err) =3D> { > - eprintln!("query system time failed - {}", err); > - continue; > - } > - }; > + let now =3D proxmox::tools::time::epoch_i64(); > + > if next > now { continue; } > =20 > let store2 =3D store.clone(); > @@ -338,7 +334,7 @@ async fn schedule_datastore_garbage_collection() { > async fn schedule_datastore_prune() { > =20 > use proxmox_backup::backup::{ > - PruneOptions, DataStore, BackupGroup, BackupDir, compute_prune_i= nfo}; > + PruneOptions, DataStore, BackupGroup, compute_prune_info}; > use proxmox_backup::server::{WorkerTask}; > use proxmox_backup::config::datastore::{self, DataStoreConfig}; > use proxmox_backup::tools::systemd::time::{ > @@ -420,13 +416,8 @@ async fn schedule_datastore_prune() { > } > }; > =20 > - let now =3D match epoch_now_u64() { > - Ok(epoch_now) =3D> epoch_now as i64, > - Err(err) =3D> { > - eprintln!("query system time failed - {}", err); > - continue; > - } > - }; > + let now =3D proxmox::tools::time::epoch_i64(); > + > if next > now { continue; } > =20 > let store2 =3D store.clone(); > @@ -457,8 +448,7 @@ async fn schedule_datastore_prune() { > "{} {}/{}/{}", > if keep { "keep" } else { "remove" }, > group.backup_type(), group.backup_id(), > - BackupDir::backup_time_to_string(info.backup= _dir.backup_time()))); > - > + info.backup_dir.backup_time_string())); > if !keep { > datastore.remove_backup_dir(&info.backup_dir= , true)?; > } > @@ -529,13 +519,8 @@ async fn schedule_datastore_sync_jobs() { > } > }; > =20 > - let now =3D match epoch_now_u64() { > - Ok(epoch_now) =3D> epoch_now as i64, > - Err(err) =3D> { > - eprintln!("query system time failed - {}", err); > - continue; > - } > - }; > + let now =3D proxmox::tools::time::epoch_i64(); > + > if next > now { continue; } > =20 > let job =3D match Job::new(worker_type, &job_id) { > diff --git a/src/bin/proxmox_backup_client/benchmark.rs b/src/bin/proxmox= _backup_client/benchmark.rs > index 9830c18..f8f989d 100644 > --- a/src/bin/proxmox_backup_client/benchmark.rs > +++ b/src/bin/proxmox_backup_client/benchmark.rs > @@ -3,7 +3,6 @@ use std::sync::Arc; > =20 > use anyhow::{Error}; > use serde_json::Value; > -use chrono::Utc; > use serde::Serialize; > =20 > use proxmox::api::{ApiMethod, RpcEnvironment}; > @@ -212,7 +211,7 @@ async fn test_upload_speed( > verbose: bool, > ) -> Result<(), Error> { > =20 > - let backup_time =3D Utc::now(); > + let backup_time =3D proxmox::tools::time::epoch_i64(); > =20 > let client =3D connect(repo.host(), repo.user())?; > record_repository(&repo); > diff --git a/src/bin/proxmox_backup_client/key.rs b/src/bin/proxmox_backu= p_client/key.rs > index 30afa4e..f60687e 100644 > --- a/src/bin/proxmox_backup_client/key.rs > +++ b/src/bin/proxmox_backup_client/key.rs > @@ -1,7 +1,6 @@ > use std::path::PathBuf; > =20 > use anyhow::{bail, format_err, Error}; > -use chrono::Local; > use serde::{Deserialize, Serialize}; > =20 > use proxmox::api::api; > @@ -112,7 +111,7 @@ fn create(kdf: Option, path: Option) -> = Result<(), Error> { > =20 > match kdf { > Kdf::None =3D> { > - let created =3D Local::now(); > + let created =3D proxmox::tools::time::epoch_i64(); > =20 > store_key_config( > &path, > @@ -180,7 +179,7 @@ fn change_passphrase(kdf: Option, path: Option) -> Result<(), Error > =20 > match kdf { > Kdf::None =3D> { > - let modified =3D Local::now(); > + let modified =3D proxmox::tools::time::epoch_i64(); > =20 > store_key_config( > &path, > diff --git a/src/client/backup_reader.rs b/src/client/backup_reader.rs > index d418571..5f002e2 100644 > --- a/src/client/backup_reader.rs > +++ b/src/client/backup_reader.rs > @@ -4,7 +4,6 @@ use std::fs::File; > use std::sync::Arc; > use std::os::unix::fs::OpenOptionsExt; > =20 > -use chrono::{DateTime, Utc}; > use futures::future::AbortHandle; > use serde_json::{json, Value}; > =20 > @@ -41,14 +40,14 @@ impl BackupReader { > datastore: &str, > backup_type: &str, > backup_id: &str, > - backup_time: DateTime, > + backup_time: i64, > debug: bool, > ) -> Result, Error> { > =20 > let param =3D json!({ > "backup-type": backup_type, > "backup-id": backup_id, > - "backup-time": backup_time.timestamp(), > + "backup-time": backup_time, > "store": datastore, > "debug": debug, > }); > diff --git a/src/client/backup_writer.rs b/src/client/backup_writer.rs > index 64c3cf2..e071911 100644 > --- a/src/client/backup_writer.rs > +++ b/src/client/backup_writer.rs > @@ -4,7 +4,6 @@ use std::sync::atomic::{AtomicUsize, Ordering}; > use std::sync::{Arc, Mutex}; > =20 > use anyhow::{bail, format_err, Error}; > -use chrono::{DateTime, Utc}; > use futures::*; > use futures::stream::Stream; > use futures::future::AbortHandle; > @@ -51,7 +50,7 @@ impl BackupWriter { > datastore: &str, > backup_type: &str, > backup_id: &str, > - backup_time: DateTime, > + backup_time: i64, > debug: bool, > benchmark: bool > ) -> Result, Error> { > @@ -59,7 +58,7 @@ impl BackupWriter { > let param =3D json!({ > "backup-type": backup_type, > "backup-id": backup_id, > - "backup-time": backup_time.timestamp(), > + "backup-time": backup_time, > "store": datastore, > "debug": debug, > "benchmark": benchmark > diff --git a/src/client/http_client.rs b/src/client/http_client.rs > index ae3704d..3fd9fb7 100644 > --- a/src/client/http_client.rs > +++ b/src/client/http_client.rs > @@ -2,7 +2,6 @@ use std::io::Write; > use std::task::{Context, Poll}; > use std::sync::{Arc, Mutex}; > =20 > -use chrono::Utc; > use anyhow::{bail, format_err, Error}; > use futures::*; > use http::Uri; > @@ -199,7 +198,7 @@ fn store_ticket_info(prefix: &str, server: &str, user= name: &str, ticket: &str, t > =20 > let mut data =3D file_get_json(&path, Some(json!({})))?; > =20 > - let now =3D Utc::now().timestamp(); > + let now =3D proxmox::tools::time::epoch_i64(); > =20 > data[server][username] =3D json!({ "timestamp": now, "ticket": ticke= t, "token": token}); > =20 > @@ -230,7 +229,7 @@ fn load_ticket_info(prefix: &str, server: &str, useri= d: &Userid) -> Option<(Stri > // usually /run/user//... > let path =3D base.place_runtime_file("tickets").ok()?; > let data =3D file_get_json(&path, None).ok()?; > - let now =3D Utc::now().timestamp(); > + let now =3D proxmox::tools::time::epoch_i64(); > let ticket_lifetime =3D tools::ticket::TICKET_LIFETIME - 60; > let uinfo =3D data[server][userid.as_str()].as_object()?; > let timestamp =3D uinfo["timestamp"].as_i64()?; > diff --git a/src/config/jobstate.rs b/src/config/jobstate.rs > index d9bffbb..b35973a 100644 > --- a/src/config/jobstate.rs > +++ b/src/config/jobstate.rs > @@ -48,7 +48,6 @@ use proxmox::tools::fs::{ > use serde::{Deserialize, Serialize}; > =20 > use crate::server::{upid_read_status, worker_is_active_local, TaskState,= UPID}; > -use crate::tools::epoch_now_u64; > =20 > #[serde(rename_all =3D "kebab-case")] > #[derive(Serialize, Deserialize)] > @@ -178,7 +177,7 @@ impl JobState { > } > } else { > Ok(JobState::Created { > - time: epoch_now_u64()? as i64 - 30, > + time: proxmox::tools::time::epoch_i64() - 30, > }) > } > } > @@ -199,7 +198,7 @@ impl Job { > jobtype: jobtype.to_string(), > jobname: jobname.to_string(), > state: JobState::Created { > - time: epoch_now_u64()? as i64, > + time: proxmox::tools::time::epoch_i64(), > }, > _lock, > }) > diff --git a/src/pxar/tools.rs b/src/pxar/tools.rs > index 2eed0f8..3fd0fc0 100644 > --- a/src/pxar/tools.rs > +++ b/src/pxar/tools.rs > @@ -115,12 +115,10 @@ fn mode_string(entry: &Entry) -> String { > } > =20 > fn format_mtime(mtime: &StatxTimestamp) -> String { > - use chrono::offset::TimeZone; > - > - match chrono::Local.timestamp_opt(mtime.secs, mtime.nanos) { > - chrono::LocalResult::Single(mtime) =3D> mtime.format("%Y-%m-%d %= H:%M:%S").to_string(), > - _ =3D> format!("{}.{}", mtime.secs, mtime.nanos), > + if let Ok(s) =3D proxmox::tools::time::strftime_local("%Y-%m-%d %H:%= M:%S", mtime.secs) { > + return s; > } > + format!("{}.{}", mtime.secs, mtime.nanos) + proxmox::tools::time::strftime_local("%Y-%m-%d %H:%M:%S", mtime.secs) + .unwrap_or_else(|_| format!("{}.{}", mtime.secs, mtime.nanos)) seems more idiomatic rust to me (and it's shorter ;)) > } > =20 > pub fn format_single_line_entry(entry: &Entry) -> String { > diff --git a/src/rrd/cache.rs b/src/rrd/cache.rs > index f08d6c9..e5e3fe0 100644 > --- a/src/rrd/cache.rs > +++ b/src/rrd/cache.rs > @@ -8,7 +8,6 @@ use lazy_static::lazy_static; > use proxmox::tools::fs::{create_path, CreateOptions}; > =20 > use crate::api2::types::{RRDMode, RRDTimeFrameResolution}; > -use crate::tools::epoch_now_f64; > =20 > use super::*; > =20 > @@ -42,7 +41,7 @@ pub fn update_value(rel_path: &str, value: f64, dst: DS= T, save: bool) -> Result< > std::fs::create_dir_all(path.parent().unwrap())?; > =20 > let mut map =3D RRD_CACHE.write().unwrap(); > - let now =3D epoch_now_f64()?; > + let now =3D proxmox::tools::time::epoch_f64(); > =20 > if let Some(rrd) =3D map.get_mut(rel_path) { > rrd.update(now, value); > diff --git a/src/server/upid.rs b/src/server/upid.rs > index 9fc5085..f829eef 100644 > --- a/src/server/upid.rs > +++ b/src/server/upid.rs > @@ -1,7 +1,6 @@ > use std::sync::atomic::{AtomicUsize, Ordering}; > =20 > use anyhow::{bail, Error}; > -use chrono::Local; > =20 > use proxmox::api::schema::{ApiStringFormat, Schema, StringSchema}; > use proxmox::const_regex; > @@ -89,7 +88,7 @@ impl UPID { > Ok(UPID { > pid, > pstart: procfs::PidStat::read_from_pid(nix::unistd::Pid::fro= m_raw(pid))?.starttime, > - starttime: Local::now().timestamp(), > + starttime: proxmox::tools::time::epoch_i64(), > task_id, > worker_type: worker_type.to_owned(), > worker_id, > diff --git a/src/server/worker_task.rs b/src/server/worker_task.rs > index 28e62ba..0f7e291 100644 > --- a/src/server/worker_task.rs > +++ b/src/server/worker_task.rs > @@ -5,7 +5,6 @@ use std::panic::UnwindSafe; > use std::sync::atomic::{AtomicBool, Ordering}; > use std::sync::{Arc, Mutex}; > =20 > -use chrono::Local; > use anyhow::{bail, format_err, Error}; > use futures::*; > use lazy_static::lazy_static; > @@ -231,9 +230,7 @@ pub fn upid_read_status(upid: &UPID) -> Result { > =20 > let mut iter =3D last_line.splitn(2, ": "); > if let Some(time_str) =3D iter.next() { > - if let Ok(endtime) =3D chrono::DateTime::parse_from_rfc3339(time= _str) { > - let endtime =3D endtime.timestamp(); > - > + if let Ok(endtime) =3D proxmox::tools::time::parse_rfc3339(time_= str) { > if let Some(rest) =3D iter.next().and_then(|rest| rest.strip= _prefix("TASK ")) { > if let Ok(state) =3D TaskState::from_endtime_and_message= (endtime, rest) { > status =3D state; > @@ -364,8 +361,9 @@ fn update_active_workers(new_upid: Option<&UPID>) -> = Result, E > }, > None =3D> { > println!("Detected stopped UPID {}", upid_str); > + let now =3D proxmox::tools::time::epoch_i64(); > let status =3D upid_read_status(&upid) > - .unwrap_or_else(|_| TaskState::Unknown { end= time: Local::now().timestamp() }); > + .unwrap_or_else(|_| TaskState::Unknown { end= time: now }); > finish_list.push(TaskListInfo { > upid, upid_str, state: Some(status) > }); > @@ -589,7 +587,7 @@ impl WorkerTask { > pub fn create_state(&self, result: &Result<(), Error>) -> TaskState = { > let warn_count =3D self.data.lock().unwrap().warn_count; > =20 > - let endtime =3D Local::now().timestamp(); > + let endtime =3D proxmox::tools::time::epoch_i64(); > =20 > if let Err(err) =3D result { > TaskState::Error { message: err.to_string(), endtime } > diff --git a/src/tools.rs b/src/tools.rs > index a3fbe00..8080777 100644 > --- a/src/tools.rs > +++ b/src/tools.rs > @@ -8,8 +8,6 @@ use std::fs::File; > use std::io::{self, BufRead, ErrorKind, Read}; > use std::os::unix::io::RawFd; > use std::path::Path; > -use std::time::Duration; > -use std::time::{SystemTime, SystemTimeError, UNIX_EPOCH}; > =20 > use anyhow::{bail, format_err, Error}; > use serde_json::Value; > @@ -547,18 +545,6 @@ pub fn file_get_non_comment_lines>( > })) > } > =20 > -pub fn epoch_now() -> Result { > - SystemTime::now().duration_since(UNIX_EPOCH) > -} > - > -pub fn epoch_now_f64() -> Result { > - Ok(epoch_now()?.as_secs_f64()) > -} > - > -pub fn epoch_now_u64() -> Result { > - Ok(epoch_now()?.as_secs()) > -} > - > pub fn setup_safe_path_env() { > std::env::set_var("PATH", "/sbin:/bin:/usr/sbin:/usr/bin"); > // Make %ENV safer - as suggested by https://perldoc.perl.org/perlse= c.html > diff --git a/src/tools/file_logger.rs b/src/tools/file_logger.rs > index c0fcab7..c41994f 100644 > --- a/src/tools/file_logger.rs > +++ b/src/tools/file_logger.rs > @@ -1,5 +1,4 @@ > use anyhow::{Error}; > -use chrono::Local; > use std::io::Write; > =20 > /// Log messages with timestamps into files > @@ -56,7 +55,10 @@ impl FileLogger { > stdout.write_all(b"\n").unwrap(); > } > =20 > - let line =3D format!("{}: {}\n", Local::now().to_rfc3339(), msg)= ; > + let now =3D proxmox::tools::time::epoch_i64(); > + let rfc3339 =3D proxmox::tools::time::epoch_to_rfc3339(now).unwr= ap(); > + > + let line =3D format!("{}: {}\n", rfc3339, msg); > self.file.write_all(line.as_bytes()).unwrap(); > } > } > diff --git a/src/tools/format.rs b/src/tools/format.rs > index 1e593ff..9894668 100644 > --- a/src/tools/format.rs > +++ b/src/tools/format.rs > @@ -1,6 +1,5 @@ > use anyhow::{Error}; > use serde_json::Value; > -use chrono::{Local, TimeZone, LocalResult}; > =20 > pub fn strip_server_file_expenstion(name: &str) -> String { > =20 > @@ -25,9 +24,10 @@ pub fn render_epoch(value: &Value, _record: &Value) ->= Result { > if value.is_null() { return Ok(String::new()); } > let text =3D match value.as_i64() { > Some(epoch) =3D> { > - match Local.timestamp_opt(epoch, 0) { > - LocalResult::Single(epoch) =3D> epoch.format("%c").to_st= ring(), > - _ =3D> epoch.to_string(), > + if let Ok(epoch_string) =3D proxmox::tools::time::strftime_l= ocal("%c", epoch as i64) { > + epoch_string > + } else { > + epoch.to_string() > } > }, > None =3D> { > diff --git a/src/tools/systemd.rs b/src/tools/systemd.rs > index 9a6439d..8f0a66d 100644 > --- a/src/tools/systemd.rs > +++ b/src/tools/systemd.rs > @@ -2,7 +2,6 @@ pub mod types; > pub mod config; > =20 > mod parse_time; > -pub mod tm_editor; > pub mod time; > =20 > use anyhow::{bail, Error}; > diff --git a/src/tools/systemd/time.rs b/src/tools/systemd/time.rs > index f76731f..1961d4b 100644 > --- a/src/tools/systemd/time.rs > +++ b/src/tools/systemd/time.rs > @@ -3,8 +3,9 @@ use std::convert::TryInto; > use anyhow::Error; > use bitflags::bitflags; > =20 > +use proxmox::tools::time::TmEditor; > + > pub use super::parse_time::*; > -use super::tm_editor::*; > =20 > bitflags!{ > #[derive(Default)] > @@ -161,7 +162,7 @@ pub fn compute_next_event( > =20 > let all_days =3D event.days.is_empty() || event.days.is_all(); > =20 > - let mut t =3D TmEditor::new(last, utc)?; > + let mut t =3D TmEditor::with_epoch(last, utc)?; > =20 > let mut count =3D 0; > =20 > diff --git a/src/tools/systemd/tm_editor.rs b/src/tools/systemd/tm_editor= .rs > deleted file mode 100644 > index 770bb28..0000000 > --- a/src/tools/systemd/tm_editor.rs > +++ /dev/null > @@ -1,119 +0,0 @@ > -use anyhow::Error; > - > -use proxmox::tools::time::*; > - > -pub struct TmEditor { > - utc: bool, > - t: libc::tm, > -} > - > -impl TmEditor { > - > - pub fn new(epoch: i64, utc: bool) -> Result { > - let t =3D if utc { gmtime(epoch)? } else { localtime(epoch)? }; > - Ok(Self { utc, t }) > - } > - > - pub fn into_epoch(mut self) -> Result { > - let epoch =3D if self.utc { timegm(&mut self.t)? } else { timelo= cal(&mut self.t)? }; > - Ok(epoch) > - } > - > - /// increases the year by 'years' and resets all smaller fields to t= heir minimum > - pub fn add_years(&mut self, years: libc::c_int) -> Result<(), Error>= { > - if years =3D=3D 0 { return Ok(()); } > - self.t.tm_mon =3D 0; > - self.t.tm_mday =3D 1; > - self.t.tm_hour =3D 0; > - self.t.tm_min =3D 0; > - self.t.tm_sec =3D 0; > - self.t.tm_year +=3D years; > - self.normalize_time() > - } > - > - /// increases the month by 'months' and resets all smaller fields to= their minimum > - pub fn add_months(&mut self, months: libc::c_int) -> Result<(), Erro= r> { > - if months =3D=3D 0 { return Ok(()); } > - self.t.tm_mday =3D 1; > - self.t.tm_hour =3D 0; > - self.t.tm_min =3D 0; > - self.t.tm_sec =3D 0; > - self.t.tm_mon +=3D months; > - self.normalize_time() > - } > - > - /// increases the day by 'days' and resets all smaller fields to the= ir minimum > - pub fn add_days(&mut self, days: libc::c_int) -> Result<(), Error> { > - if days =3D=3D 0 { return Ok(()); } > - self.t.tm_hour =3D 0; > - self.t.tm_min =3D 0; > - self.t.tm_sec =3D 0; > - self.t.tm_mday +=3D days; > - self.normalize_time() > - } > - > - pub fn year(&self) -> libc::c_int { self.t.tm_year + 1900 } // see m= an mktime > - pub fn month(&self) -> libc::c_int { self.t.tm_mon + 1 } > - pub fn day(&self) -> libc::c_int { self.t.tm_mday } > - pub fn hour(&self) -> libc::c_int { self.t.tm_hour } > - pub fn min(&self) -> libc::c_int { self.t.tm_min } > - pub fn sec(&self) -> libc::c_int { self.t.tm_sec } > - > - // Note: tm_wday (0-6, Sunday =3D 0) =3D> convert to Sunday =3D 6 > - pub fn day_num(&self) -> libc::c_int { > - (self.t.tm_wday + 6) % 7 > - } > - > - pub fn set_time(&mut self, hour: libc::c_int, min: libc::c_int, sec:= libc::c_int) -> Result<(), Error> { > - self.t.tm_hour =3D hour; > - self.t.tm_min =3D min; > - self.t.tm_sec =3D sec; > - self.normalize_time() > - } > - > - pub fn set_min_sec(&mut self, min: libc::c_int, sec: libc::c_int) ->= Result<(), Error> { > - self.t.tm_min =3D min; > - self.t.tm_sec =3D sec; > - self.normalize_time() > - } > - > - fn normalize_time(&mut self) -> Result<(), Error> { > - // libc normalizes it for us > - if self.utc { > - timegm(&mut self.t)?; > - } else { > - timelocal(&mut self.t)?; > - } > - Ok(()) > - } > - > - pub fn set_sec(&mut self, v: libc::c_int) -> Result<(), Error> { > - self.t.tm_sec =3D v; > - self.normalize_time() > - } > - > - pub fn set_min(&mut self, v: libc::c_int) -> Result<(), Error> { > - self.t.tm_min =3D v; > - self.normalize_time() > - } > - > - pub fn set_hour(&mut self, v: libc::c_int) -> Result<(), Error> { > - self.t.tm_hour =3D v; > - self.normalize_time() > - } > - > - pub fn set_mday(&mut self, v: libc::c_int) -> Result<(), Error> { > - self.t.tm_mday =3D v; > - self.normalize_time() > - } > - > - pub fn set_mon(&mut self, v: libc::c_int) -> Result<(), Error> { > - self.t.tm_mon =3D v - 1; > - self.normalize_time() > - } > - > - pub fn set_year(&mut self, v: libc::c_int) -> Result<(), Error> { > - self.t.tm_year =3D v - 1900; > - self.normalize_time() > - } > -} > diff --git a/src/tools/ticket.rs b/src/tools/ticket.rs > index bada0ef..4462ee3 100644 > --- a/src/tools/ticket.rs > +++ b/src/tools/ticket.rs > @@ -11,7 +11,6 @@ use openssl::sign::{Signer, Verifier}; > use percent_encoding::{percent_decode_str, percent_encode, AsciiSet}; > =20 > use crate::api2::types::Userid; > -use crate::tools::epoch_now_u64; > =20 > pub const TICKET_LIFETIME: i64 =3D 3600 * 2; // 2 hours > =20 > @@ -69,7 +68,7 @@ where > Ok(Self { > prefix: Cow::Borrowed(prefix), > data: data.to_string(), > - time: epoch_now_u64()? as i64, > + time: proxmox::tools::time::epoch_i64(), > signature: None, > _type_marker: PhantomData, > }) > @@ -174,7 +173,7 @@ where > None =3D> bail!("invalid ticket without signature"), > }; > =20 > - let age =3D epoch_now_u64()? as i64 - self.time; > + let age =3D proxmox::tools::time::epoch_i64() - self.time; > if age < time_frame.start { > bail!("invalid ticket - timestamp newer than expected"); > } > @@ -272,7 +271,6 @@ mod test { > =20 > use super::Ticket; > use crate::api2::types::Userid; > - use crate::tools::epoch_now_u64; > =20 > fn simple_test(key: &PKey, aad: Option<&str>, modify: F) > where > @@ -314,7 +312,7 @@ mod test { > false > }); > simple_test(&key, None, |t| { > - t.change_time(epoch_now_u64().unwrap() as i64 + 0x1000_0000)= ; > + t.change_time(proxmox::tools::time::epoch_i64() + 0x1000_000= 0); > false > }); > } > --=20 > 2.20.1 >=20 >=20 > _______________________________________________ > pve-devel mailing list > pve-devel@lists.proxmox.com > https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel >=20 >=20 >=20 =