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)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id DD40A66B86 for ; Tue, 28 Jul 2020 12:33:54 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id C63CB23778 for ; Tue, 28 Jul 2020 12:33:24 +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)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS id A838423748 for ; Tue, 28 Jul 2020 12:33:22 +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 6EF2B433CD for ; Tue, 28 Jul 2020 12:33:22 +0200 (CEST) From: Wolfgang Bumiller To: pbs-devel@lists.proxmox.com Date: Tue, 28 Jul 2020 12:33:17 +0200 Message-Id: <20200728103321.16843-4-w.bumiller@proxmox.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200728103321.16843-1-w.bumiller@proxmox.com> References: <20200728103321.16843-1-w.bumiller@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.023 Adjusted score from AWL reputation of From: address KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment 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. [mod.rs] Subject: [pbs-devel] [PATCH pxar 2/6] introduce StatxTimestamp helper type X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 28 Jul 2020 10:33:54 -0000 Signed-off-by: Wolfgang Bumiller --- src/format/mod.rs | 103 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/src/format/mod.rs b/src/format/mod.rs index 0f9db79..085b8b9 100644 --- a/src/format/mod.rs +++ b/src/format/mod.rs @@ -43,6 +43,7 @@ use std::io; use std::mem::size_of; use std::os::unix::ffi::OsStrExt; use std::path::Path; +use std::time::{Duration, SystemTime}; use endian_trait::Endian; use siphasher::sip::SipHasher24; @@ -194,6 +195,108 @@ impl Display for Header { } } +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum SignedDuration { + Positive(Duration), + Negative(Duration), +} + +#[derive(Clone, Debug, Default, Endian, Eq, PartialEq)] +#[repr(C)] +pub struct StatxTimestamp { + /// Seconds since the epoch (unix time). + pub secs: i64, + + /// Nanoseconds since this struct's `secs`. + pub nanos: u32, +} + +impl From for StatxTimestamp { + fn from(time: SystemTime) -> Self { + match time.duration_since(SystemTime::UNIX_EPOCH) { + Ok(positive) => Self::from_duration_since_epoch(positive), + Err(negative) => Self::from_duration_before_epoch(negative.duration()), + } + } +} + +impl StatxTimestamp { + /// `const` version of `Default` + pub const fn zero() -> Self { + Self { secs: 0, nanos: 0 } + } + + /// Turn a positive duration relative to the unix epoch into a time stamp. + pub fn from_duration_since_epoch(duration: Duration) -> Self { + Self { + secs: duration.as_secs() as i64, + nanos: duration.subsec_nanos(), + } + } + + /// Turn a *negative* duration from relative to the unix epoch into a time stamp. + pub fn from_duration_before_epoch(duration: Duration) -> Self { + match duration.subsec_nanos() { + 0 => Self { + secs: duration.as_secs() as i64, + nanos: 0, + }, + nanos => Self { + secs: -(duration.as_secs() as i64) - 1, + nanos: 1_000_000_000 - nanos, + }, + } + } + + /// Get the duration since the epoch. an `Ok` value is a positive duration, an `Err` value is a + /// negative duration. + pub fn to_duration(&self) -> SignedDuration { + if self.secs >= 0 { + SignedDuration::Positive(Duration::new(self.secs as u64, self.nanos)) + } else { + SignedDuration::Negative(Duration::new( + -(self.secs + 1) as u64, + 1_000_000_000 - self.nanos, + )) + } + } + + /// Get a `std::time::SystemTime` from this time stamp. + pub fn system_time(&self) -> SystemTime { + match self.to_duration() { + SignedDuration::Positive(positive) => SystemTime::UNIX_EPOCH + positive, + SignedDuration::Negative(negative) => SystemTime::UNIX_EPOCH - negative, + } + } +} + +#[test] +fn test_statx_timestamp() { + const MAY_1_2015_1530: i64 = 1430487000; + let system_time = SystemTime::UNIX_EPOCH + Duration::new(MAY_1_2015_1530 as u64, 1_000_000); + let tx = StatxTimestamp::from(system_time); + assert_eq!( + tx, + StatxTimestamp { + secs: MAY_1_2015_1530, + nanos: 1_000_000, + } + ); + assert_eq!(tx.system_time(), system_time); + + const MAY_1_1960_1530: i64 = -305112600; + let system_time = SystemTime::UNIX_EPOCH - Duration::new(-MAY_1_1960_1530 as u64, 1_000_000); + let tx = StatxTimestamp::from(system_time); + assert_eq!( + tx, + StatxTimestamp { + secs: MAY_1_1960_1530 - 1, + nanos: 999_000_000, + } + ); + assert_eq!(tx.system_time(), system_time); +} + #[derive(Clone, Debug, Default, Endian)] #[cfg_attr(feature = "test-harness", derive(Eq, PartialEq))] #[repr(C)] -- 2.20.1