summaryrefslogtreecommitdiff
path: root/vendor/android-tzdata/src/tzdata.rs
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-07-15 16:37:08 -0600
committermo khan <mo@mokhan.ca>2025-07-17 16:30:22 -0600
commit45df4d0d9b577fecee798d672695fe24ff57fb1b (patch)
tree1b99bf645035b58e0d6db08c7a83521f41f7a75b /vendor/android-tzdata/src/tzdata.rs
parentf94f79608393d4ab127db63cc41668445ef6b243 (diff)
feat: migrate from Cedar to SpiceDB authorization system
This is a major architectural change that replaces the Cedar policy-based authorization system with SpiceDB's relation-based authorization. Key changes: - Migrate from Rust to Go implementation - Replace Cedar policies with SpiceDB schema and relationships - Switch from envoy `ext_authz` with Cedar to SpiceDB permission checks - Update build system and dependencies for Go ecosystem - Maintain Envoy integration for external authorization This change enables more flexible permission modeling through SpiceDB's Google Zanzibar inspired relation-based system, supporting complex hierarchical permissions that were difficult to express in Cedar. Breaking change: Existing Cedar policies and Rust-based configuration will no longer work and need to be migrated to SpiceDB schema.
Diffstat (limited to 'vendor/android-tzdata/src/tzdata.rs')
-rw-r--r--vendor/android-tzdata/src/tzdata.rs166
1 files changed, 0 insertions, 166 deletions
diff --git a/vendor/android-tzdata/src/tzdata.rs b/vendor/android-tzdata/src/tzdata.rs
deleted file mode 100644
index 92e4b621..00000000
--- a/vendor/android-tzdata/src/tzdata.rs
+++ /dev/null
@@ -1,166 +0,0 @@
-//! Logic was mainly ported from https://android.googlesource.com/platform/libcore/+/jb-mr2-release/luni/src/main/java/libcore/util/ZoneInfoDB.java
-
-use core::{cmp::Ordering, convert::TryInto};
-use std::{
- fs::File,
- io::{self, ErrorKind, Read, Seek, SeekFrom},
-};
-
-// The database uses 32-bit (4 byte) integers.
-const TZ_INT_SIZE: usize = 4;
-// The first 12 bytes contain a special version string.
-const MAGIC_SIZE: usize = 12;
-const HEADER_SIZE: usize = MAGIC_SIZE + 3 * TZ_INT_SIZE;
-// The database reserves 40 bytes for each id.
-const TZ_NAME_SIZE: usize = 40;
-const INDEX_ENTRY_SIZE: usize = TZ_NAME_SIZE + 3 * TZ_INT_SIZE;
-const TZDATA_LOCATIONS: [TzdataLocation; 2] = [
- TzdataLocation {
- env_var: "ANDROID_DATA",
- path: "/misc/zoneinfo/",
- },
- TzdataLocation {
- env_var: "ANDROID_ROOT",
- path: "/usr/share/zoneinfo/",
- },
-];
-
-#[derive(Debug)]
-struct TzdataLocation {
- env_var: &'static str,
- path: &'static str,
-}
-
-#[derive(Debug, Clone, Copy)]
-struct Header {
- index_offset: usize,
- data_offset: usize,
- _zonetab_offset: usize,
-}
-
-#[derive(Debug)]
-struct Index(Vec<u8>);
-
-#[derive(Debug, Clone, Copy)]
-struct IndexEntry<'a> {
- _name: &'a [u8],
- offset: usize,
- length: usize,
- _raw_utc_offset: usize,
-}
-
-pub(super) fn find_file() -> Result<File, io::Error> {
- for location in &TZDATA_LOCATIONS {
- if let Ok(env_value) = std::env::var(location.env_var) {
- if let Ok(file) = File::open(format!("{}{}tzdata", env_value, location.path)) {
- return Ok(file);
- }
- }
- }
- Err(io::Error::from(io::ErrorKind::NotFound))
-}
-
-pub(super) fn find_tz_data_in_file(
- mut file: impl Read + Seek,
- tz_name: &str,
-) -> Result<Vec<u8>, io::Error> {
- let header = Header::new(&mut file)?;
- let index = Index::new(&mut file, header)?;
- if let Some(entry) = index.find_entry(tz_name) {
- file.seek(SeekFrom::Start((entry.offset + header.data_offset) as u64))?;
- let mut tz_data = vec![0u8; entry.length];
- file.read_exact(&mut tz_data)?;
- Ok(tz_data)
- } else {
- Err(io::Error::from(ErrorKind::NotFound))
- }
-}
-
-impl Header {
- fn new(mut file: impl Read + Seek) -> Result<Self, io::Error> {
- let mut buf = [0; HEADER_SIZE];
- file.read_exact(&mut buf)?;
- if !buf.starts_with(b"tzdata") || buf[MAGIC_SIZE - 1] != 0u8 {
- return Err(io::Error::new(
- io::ErrorKind::InvalidData,
- "invalid magic number",
- ));
- }
- Ok(Self {
- index_offset: parse_tz_int(&buf, MAGIC_SIZE) as usize,
- data_offset: parse_tz_int(&buf, MAGIC_SIZE + TZ_INT_SIZE) as usize,
- _zonetab_offset: parse_tz_int(&buf, MAGIC_SIZE + 2 * TZ_INT_SIZE) as usize,
- })
- }
-}
-
-impl Index {
- fn new(mut file: impl Read + Seek, header: Header) -> Result<Self, io::Error> {
- file.seek(SeekFrom::Start(header.index_offset as u64))?;
- let size = header.data_offset - header.index_offset;
- let mut bytes = vec![0; size];
- file.read_exact(&mut bytes)?;
- Ok(Self(bytes))
- }
-
- fn find_entry(&self, name: &str) -> Option<IndexEntry> {
- let name_bytes = name.as_bytes();
- let name_len = name_bytes.len();
- if name_len > TZ_NAME_SIZE {
- return None;
- }
-
- let zeros = [0u8; TZ_NAME_SIZE];
- let cmp = |chunk: &&[u8]| -> Ordering {
- // tz names always have TZ_NAME_SIZE bytes and are right-padded with 0s
- // so we check that a chunk starts with `name` and the remaining bytes are 0
- chunk[..name_len]
- .cmp(name_bytes)
- .then_with(|| chunk[name_len..TZ_NAME_SIZE].cmp(&zeros[name_len..]))
- };
-
- let chunks: Vec<_> = self.0.chunks_exact(INDEX_ENTRY_SIZE).collect();
- chunks
- .binary_search_by(cmp)
- .map(|idx| IndexEntry::new(chunks[idx]))
- .ok()
- }
-}
-
-impl<'a> IndexEntry<'a> {
- fn new(bytes: &'a [u8]) -> Self {
- Self {
- _name: bytes[..TZ_NAME_SIZE]
- .splitn(2, |&b| b == 0u8)
- .next()
- .unwrap(),
- offset: parse_tz_int(bytes, TZ_NAME_SIZE) as usize,
- length: parse_tz_int(bytes, TZ_NAME_SIZE + TZ_INT_SIZE) as usize,
- _raw_utc_offset: parse_tz_int(bytes, TZ_NAME_SIZE + 2 * TZ_INT_SIZE) as usize,
- }
- }
-}
-
-/// Panics if slice does not contain [TZ_INT_SIZE] bytes beginning at start.
-fn parse_tz_int(slice: &[u8], start: usize) -> u32 {
- u32::from_be_bytes(slice[start..start + TZ_INT_SIZE].try_into().unwrap())
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
- use std::fs::File;
- use std::io::Cursor;
-
- #[test]
- fn parse() {
- let mut archive = File::open("tests/resources/tzdata.zip").unwrap();
- let mut zip = zip::ZipArchive::new(&mut archive).unwrap();
- let mut file = zip.by_index(0).unwrap();
- let mut data = Vec::new();
- file.read_to_end(&mut data).unwrap();
- let cursor = Cursor::new(data);
- let tz = find_tz_data_in_file(cursor, "Europe/Kiev").unwrap();
- assert!(tz.starts_with(b"TZif2"));
- }
-}