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 8051066AF5 for ; Tue, 28 Jul 2020 12:33:26 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 7D6D2237B3 for ; Tue, 28 Jul 2020 12:33:26 +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 7F08423768 for ; Tue, 28 Jul 2020 12:33:23 +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 498F5433C9 for ; Tue, 28 Jul 2020 12:33:23 +0200 (CEST) From: Wolfgang Bumiller To: pbs-devel@lists.proxmox.com Date: Tue, 28 Jul 2020 12:33:19 +0200 Message-Id: <20200728103321.16843-6-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.229 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. [lib.rs, errors.rs, mod.rs] Subject: [pbs-devel] [PATCH pxar 4/6] implement Entry v2 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:26 -0000 Signed-off-by: Wolfgang Bumiller --- src/decoder/mod.rs | 21 ++++++++++++++++----- src/errors.rs | 25 ------------------------- src/format/mod.rs | 46 ++++++++++++++++++++++++++++++++++------------ src/lib.rs | 28 +++++++++++++++------------- 4 files changed, 65 insertions(+), 55 deletions(-) delete mode 100644 src/errors.rs diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 9410942..e5b6d2c 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -360,11 +360,22 @@ impl DecoderImpl { self.entry.kind = EntryKind::Hardlink(self.read_hardlink().await?); Ok(Some(self.entry.take())) - } else if header.htype == format::PXAR_ENTRY { - self.entry.metadata = Metadata { - stat: seq_read_entry(&mut self.input).await?, - ..Default::default() - }; + } else if header.htype == format::PXAR_ENTRY || header.htype == format::PXAR_ENTRY_V1 { + if header.htype == format::PXAR_ENTRY { + self.entry.metadata = Metadata { + stat: seq_read_entry(&mut self.input).await?, + ..Default::default() + }; + } else if header.htype == format::PXAR_ENTRY_V1 { + let stat: format::Entry_V1 = seq_read_entry(&mut self.input).await?; + + self.entry.metadata = Metadata { + stat: stat.into(), + ..Default::default() + }; + } else { + unreachable!(); + } self.current_header = unsafe { mem::zeroed() }; diff --git a/src/errors.rs b/src/errors.rs deleted file mode 100644 index 8983e98..0000000 --- a/src/errors.rs +++ /dev/null @@ -1,25 +0,0 @@ -use std::error::Error; -use std::fmt; - -#[derive(Clone, Debug)] -pub enum TimeError { - Underflow(std::time::SystemTimeError), - Overflow(std::time::Duration), -} - -impl fmt::Display for TimeError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - TimeError::Underflow(st) => st.fmt(f), - TimeError::Overflow(dur) => write!(f, "timestamp out of range: {:?}", dur), - } - } -} - -impl Error for TimeError {} - -impl From for TimeError { - fn from(t: std::time::SystemTimeError) -> Self { - TimeError::Underflow(t) - } -} diff --git a/src/format/mod.rs b/src/format/mod.rs index 085b8b9..ec61e15 100644 --- a/src/format/mod.rs +++ b/src/format/mod.rs @@ -78,7 +78,10 @@ pub mod mode { pub const ISVTX : u64 = 0o0001000; } -pub const PXAR_ENTRY: u64 = 0x11da850a1c1cceff; +/// Beginning of an entry (current version). +pub const PXAR_ENTRY: u64 = 0xd5956474e588acef; +/// Previous version of the entry struct +pub const PXAR_ENTRY_V1: u64 = 0x11da850a1c1cceff; pub const PXAR_FILENAME: u64 = 0x16701121063917b3; pub const PXAR_SYMLINK: u64 = 0x27f971e7dbf5dc5f; pub const PXAR_DEVICE: u64 = 0x9fc9e906586d5ce9; @@ -300,7 +303,7 @@ fn test_statx_timestamp() { #[derive(Clone, Debug, Default, Endian)] #[cfg_attr(feature = "test-harness", derive(Eq, PartialEq))] #[repr(C)] -pub struct Entry { +pub struct Entry_V1 { pub mode: u64, pub flags: u64, pub uid: u32, @@ -308,6 +311,29 @@ pub struct Entry { pub mtime: u64, } +impl Into for Entry_V1 { + fn into(self) -> Entry { + Entry { + mode: self.mode, + flags: self.flags, + uid: self.uid, + gid: self.gid, + mtime: StatxTimestamp::from_duration_since_epoch(Duration::from_nanos(self.mtime)), + } + } +} + +#[derive(Clone, Debug, Default, Endian)] +#[cfg_attr(feature = "test-harness", derive(Eq, PartialEq))] +#[repr(C)] +pub struct Entry { + pub mode: u64, + pub flags: u64, + pub uid: u32, + pub gid: u32, + pub mtime: StatxTimestamp, +} + /// Builder pattern methods. impl Entry { pub const fn mode(self, mode: u64) -> Self { @@ -326,7 +352,7 @@ impl Entry { Self { gid, ..self } } - pub const fn mtime(self, mtime: u64) -> Self { + pub const fn mtime(self, mtime: StatxTimestamp) -> Self { Self { mtime, ..self } } @@ -363,9 +389,10 @@ impl Entry { /// Convenience accessor methods. impl Entry { - /// Get the mtime as duration since the epoch. - pub fn mtime_as_duration(&self) -> std::time::Duration { - std::time::Duration::from_nanos(self.mtime) + /// Get the mtime as duration since the epoch. an `Ok` value is a positive duration, an `Err` + /// value is a negative duration. + pub fn mtime_as_duration(&self) -> SignedDuration { + self.mtime.to_duration() } /// Get the file type portion of the mode bitfield. @@ -449,12 +476,7 @@ impl From<&std::fs::Metadata> for Entry { .mode(meta.mode() as u64); let this = match meta.modified() { - Ok(mtime) => this.mtime( - mtime - .duration_since(std::time::SystemTime::UNIX_EPOCH) - .map(|dur| dur.as_nanos() as u64) - .unwrap_or(0u64), - ), + Ok(mtime) => this.mtime(mtime.into()), Err(_) => this, }; diff --git a/src/lib.rs b/src/lib.rs index 5d1b781..a58ec30 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,6 @@ //! //! This implements a reader and writer for the proxmox archive format (.pxar). -use std::convert::TryFrom; use std::ffi::OsStr; use std::mem; use std::path::{Path, PathBuf}; @@ -20,7 +19,6 @@ pub mod accessor; pub mod binary_tree_array; pub mod decoder; pub mod encoder; -pub mod errors; /// Reexport of `format::Entry`. Since this conveys mostly information found via the `stat` syscall /// we mostly use this name for public interfaces. @@ -125,8 +123,9 @@ impl Metadata { self.stat.is_socket() } - /// Get the mtime as duration since the epoch. - pub fn mtime_as_duration(&self) -> std::time::Duration { + /// Get the mtime as duration since the epoch. an `Ok` value is a positive duration, an `Err` + /// value is a negative duration. + pub fn mtime_as_duration(&self) -> format::SignedDuration { self.stat.mtime_as_duration() } @@ -165,7 +164,7 @@ impl MetadataBuilder { flags: 0, uid: 0, gid: 0, - mtime: 0, + mtime: format::StatxTimestamp::zero(), }, xattrs: Vec::new(), acl: Acl { @@ -198,17 +197,20 @@ impl MetadataBuilder { self } - /// Set the modification time from a system time. - pub fn mtime(self, mtime: std::time::SystemTime) -> Result { - self.mtime_unix(mtime.duration_since(std::time::SystemTime::UNIX_EPOCH)?) + /// Set the modification time from a statx timespec value. + pub fn mtime_full(mut self, mtime: format::StatxTimestamp) -> Self { + self.inner.stat.mtime = mtime; + self } /// Set the modification time from a duration since the epoch (`SystemTime::UNIX_EPOCH`). - pub fn mtime_unix(mut self, mtime: std::time::Duration) -> Result { - let nanos = - u64::try_from(mtime.as_nanos()).map_err(|_| errors::TimeError::Overflow(mtime))?; - self.inner.stat.mtime = nanos; - Ok(self) + pub fn mtime_unix(self, mtime: std::time::Duration) -> Self { + self.mtime_full(format::StatxTimestamp::from_duration_since_epoch(mtime)) + } + + /// Set the modification time from a system time. + pub fn mtime(self, mtime: std::time::SystemTime) -> Self { + self.mtime_full(mtime.into()) } /// Set the ownership information. -- 2.20.1