summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2020-03-27 10:30:20 +0100
committerJustus Winter <justus@sequoia-pgp.org>2020-03-27 10:44:39 +0100
commit95289f9bbacf67b283f4ce6542407ce7280a388c (patch)
treec3d7131623cd8f06ba14ec3d17d9dbb1f92a9faa
parent70a96487b25557c3b1ffcba4b61cc1140e76935a (diff)
openpgp: Add a no-dependency mechanism to format timestamps.
-rw-r--r--Cargo.lock1
-rw-r--r--openpgp/Cargo.toml1
-rw-r--r--openpgp/src/fmt.rs52
3 files changed, 54 insertions, 0 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 6ac5b924..fa1e93e9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1667,6 +1667,7 @@ dependencies = [
"lalrpop 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lalrpop-util 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
"memsec 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)",
"nettle 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"quickcheck 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/openpgp/Cargo.toml b/openpgp/Cargo.toml
index 11ce5934..c63b5ee6 100644
--- a/openpgp/Cargo.toml
+++ b/openpgp/Cargo.toml
@@ -30,6 +30,7 @@ flate2 = { version = "1.0.1", optional = true }
idna = "0.2"
lalrpop-util = "0.17"
lazy_static = "1.3"
+libc = "0.2"
memsec = "0.5.6"
nettle = "7"
quickcheck = { version = "0.9", default-features = false }
diff --git a/openpgp/src/fmt.rs b/openpgp/src/fmt.rs
index 73d42fa0..6429c79f 100644
--- a/openpgp/src/fmt.rs
+++ b/openpgp/src/fmt.rs
@@ -261,6 +261,48 @@ pub(crate) fn from_hex(hex: &str, pretty: bool) -> Result<Vec<u8>> {
Ok(bytes)
}
+/// Formats the given time using ISO 8601.
+///
+/// This is a no-dependency, best-effort mechanism. If the given time
+/// is not representable using unsigned UNIX time, we return the debug
+/// formatting.
+pub(crate) fn time(t: &std::time::SystemTime) -> String {
+ extern "C" {
+ fn strftime(
+ s: *mut libc::c_char,
+ max: libc::size_t,
+ format: *const libc::c_char,
+ tm: *const libc::tm,
+ ) -> usize;
+ }
+
+ let t = match t.duration_since(std::time::UNIX_EPOCH) {
+ Ok(t) => t.as_secs() as libc::time_t,
+ Err(_) => return format!("{:?}", t),
+ };
+ let fmt = b"%Y-%m-%dT%H:%M:%SZ\x00";
+ assert_eq!(b"2020-03-26T10:08:10Z\x00".len(), 21);
+ let mut s = [0u8; 21];
+
+ unsafe {
+ let mut tm: libc::tm = std::mem::zeroed();
+
+ #[cfg(unix)]
+ libc::gmtime_r(&t, &mut tm);
+ #[cfg(windows)]
+ libc::gmtime_s(&mut tm, &t);
+
+ strftime(s.as_mut_ptr() as *mut libc::c_char,
+ s.len(),
+ fmt.as_ptr() as *const libc::c_char,
+ &tm);
+ }
+
+ std::ffi::CStr::from_bytes_with_nul(&s)
+ .expect("strftime nul terminates string")
+ .to_string_lossy().into()
+}
+
#[cfg(test)]
mod test {
#[test]
@@ -389,4 +431,14 @@ mod test {
type\n\
");
}
+
+ #[test]
+ fn time() {
+ use super::time;
+ use crate::types::Timestamp;
+ let t = |epoch| -> std::time::SystemTime {
+ Timestamp::from(epoch).into()
+ };
+ assert_eq!(&time(&t(1585217290)), "2020-03-26T10:08:10Z");
+ }
}