lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

commit 0e5be34d9160741a4ef74681ce2940463347cd71
parent c0cf137e7edae899cc0188aa2058ea3b0d399df0
Author: triesap <tyson@radroots.org>
Date:   Wed, 12 Aug 2026 17:16:34 +0000

sqlite: normalize native metadata portably

- preserve checked device conversion across Linux and macOS native metadata
- normalize mode and link widths behind private generic helpers
- keep service host Unix mode handling warning-free across targets
- preserve the sealed public API and isolate the pending Step 075 changes

Diffstat:
Mcrates/service_host/src/admin/unix.rs | 11+++++++++--
Mcrates/service_sqlite/src/authority.rs | 38+++++++++++++++++++-------------------
Mcrates/service_sqlite/src/backup/capture.rs | 12++++++------
Mcrates/service_sqlite/src/backup/verify.rs | 8++++----
Mcrates/service_sqlite/src/initialize.rs | 22+++++++++++-----------
Mcrates/service_sqlite/src/lib.rs | 2++
Acrates/service_sqlite/src/native_metadata.rs | 43+++++++++++++++++++++++++++++++++++++++++++
Mcrates/service_sqlite/src/open.rs | 130++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Mcrates/service_sqlite/src/restore/finalize.rs | 8++++----
Mcrates/service_sqlite/src/restore/marker.rs | 6+++---
Mcrates/service_sqlite/src/restore/recover.rs | 14+++++++-------
Mcrates/service_sqlite/src/restore/stage.rs | 23++++++++++++-----------
Mcrates/service_sqlite/src/status/disk.rs | 2+-
Mcrates/service_sqlite/tests/package_boundary.rs | 26++++++++++++++++++++++++--
14 files changed, 214 insertions(+), 131 deletions(-)

diff --git a/crates/service_host/src/admin/unix.rs b/crates/service_host/src/admin/unix.rs @@ -174,7 +174,7 @@ impl UnixAdminSocketWriterAuthority { } else { Mode::RWXU }; - let directory_mode: u32 = directory_permissions.bits().into(); + let directory_mode = normalize_mode(directory_permissions.bits()); fchmod(&directory, directory_permissions).map_err(|error| { UnixAdminSocketError::RuntimeDirectoryPermissions { kind: errno_kind(error), @@ -228,6 +228,13 @@ impl UnixAdminSocketWriterAuthority { } } +fn normalize_mode<T>(raw: T) -> u32 +where + T: Into<u32>, +{ + raw.into() +} + /// A bound Unix admin listener with policy-aligned modes and identity-safe cleanup. pub struct UnixAdminSocketBinding { listener: UnixListener, @@ -564,7 +571,7 @@ mod tests { assert_eq!(UNIX_ADMIN_OWNER_SOCKET_MODE, 0o600); assert_eq!(UNIX_ADMIN_GROUP_DIRECTORY_MODE, 0o750); assert_eq!(UNIX_ADMIN_GROUP_SOCKET_MODE, 0o660); - assert_eq!(u32::from(Mode::RWXU.bits()), 0o700); + assert_eq!(normalize_mode(Mode::RWXU.bits()), 0o700); } #[cfg(target_os = "linux")] diff --git a/crates/service_sqlite/src/authority.rs b/crates/service_sqlite/src/authority.rs @@ -193,7 +193,7 @@ fn acquire_supported(paths: &ServiceSqlitePaths) -> Result<WriterAuthority, Writ validate_directory( FileType::from_raw_mode(directory_status.st_mode).is_dir(), directory_status.st_uid, - u32::from(directory_status.st_mode), + crate::native_metadata::mode(directory_status.st_mode), geteuid().as_raw(), )?; @@ -207,7 +207,7 @@ fn acquire_supported(paths: &ServiceSqlitePaths) -> Result<WriterAuthority, Writ let lock_status = fstat(&descriptor).map_err(|_| WriterAuthorityCause::LockUnavailable)?; validate_lock( FileType::from_raw_mode(lock_status.st_mode).is_file(), - u64::from(lock_status.st_nlink), + crate::native_metadata::link_count(lock_status.st_nlink), lock_status.st_uid, geteuid().as_raw(), )?; @@ -215,13 +215,13 @@ fn acquire_supported(paths: &ServiceSqlitePaths) -> Result<WriterAuthority, Writ .map_err(|_| WriterAuthorityCause::LockUnavailable)?; let lock_status = fstat(&descriptor).map_err(|_| WriterAuthorityCause::LockUnavailable)?; - if u32::from(lock_status.st_mode) & 0o777 != 0o600 { + if crate::native_metadata::mode(lock_status.st_mode) & 0o777 != 0o600 { return Err(WriterAuthorityCause::LockUnavailable); } - let directory_device = u64::try_from(directory_status.st_dev) + let directory_device = crate::native_metadata::device(directory_status.st_dev) .map_err(|_| WriterAuthorityCause::StateDirectoryUnavailable)?; - let lock_device = - u64::try_from(lock_status.st_dev).map_err(|_| WriterAuthorityCause::LockUnavailable)?; + let lock_device = crate::native_metadata::device(lock_status.st_dev) + .map_err(|_| WriterAuthorityCause::LockUnavailable)?; let file = File::from(descriptor); let directory = File::from(directory); match FileExt::try_lock_exclusive(&file) { @@ -313,16 +313,16 @@ fn validate_authority_binding( fstat(&authority.directory).map_err(|_| WriterAuthorityCause::Mismatched)?; let current_directory_status = fstat(&current_directory).map_err(|_| WriterAuthorityCause::Mismatched)?; - let held_directory_device = - u64::try_from(held_directory.st_dev).map_err(|_| WriterAuthorityCause::Mismatched)?; - let current_directory_device = u64::try_from(current_directory_status.st_dev) + let held_directory_device = crate::native_metadata::device(held_directory.st_dev) + .map_err(|_| WriterAuthorityCause::Mismatched)?; + let current_directory_device = crate::native_metadata::device(current_directory_status.st_dev) .map_err(|_| WriterAuthorityCause::Mismatched)?; if !FileType::from_raw_mode(held_directory.st_mode).is_dir() || held_directory.st_uid != geteuid().as_raw() - || u32::from(held_directory.st_mode) & 0o022 != 0 + || crate::native_metadata::mode(held_directory.st_mode) & 0o022 != 0 || !FileType::from_raw_mode(current_directory_status.st_mode).is_dir() || current_directory_status.st_uid != geteuid().as_raw() - || u32::from(current_directory_status.st_mode) & 0o022 != 0 + || crate::native_metadata::mode(current_directory_status.st_mode) & 0o022 != 0 || held_directory_device != authority.directory_device || held_directory.st_ino != authority.directory_inode || current_directory_device != authority.directory_device @@ -346,18 +346,18 @@ fn validate_authority_binding( ) .map_err(|_| WriterAuthorityCause::Mismatched)?; let current_lock_status = fstat(&current_lock).map_err(|_| WriterAuthorityCause::Mismatched)?; - let held_lock_device = - u64::try_from(held_lock.st_dev).map_err(|_| WriterAuthorityCause::Mismatched)?; - let current_lock_device = - u64::try_from(current_lock_status.st_dev).map_err(|_| WriterAuthorityCause::Mismatched)?; + let held_lock_device = crate::native_metadata::device(held_lock.st_dev) + .map_err(|_| WriterAuthorityCause::Mismatched)?; + let current_lock_device = crate::native_metadata::device(current_lock_status.st_dev) + .map_err(|_| WriterAuthorityCause::Mismatched)?; if !FileType::from_raw_mode(held_lock.st_mode).is_file() - || u64::from(held_lock.st_nlink) != 1 + || crate::native_metadata::link_count(held_lock.st_nlink) != 1 || held_lock.st_uid != geteuid().as_raw() - || u32::from(held_lock.st_mode) & 0o777 != 0o600 + || crate::native_metadata::mode(held_lock.st_mode) & 0o777 != 0o600 || !FileType::from_raw_mode(current_lock_status.st_mode).is_file() - || u64::from(current_lock_status.st_nlink) != 1 + || crate::native_metadata::link_count(current_lock_status.st_nlink) != 1 || current_lock_status.st_uid != geteuid().as_raw() - || u32::from(current_lock_status.st_mode) & 0o777 != 0o600 + || crate::native_metadata::mode(current_lock_status.st_mode) & 0o777 != 0o600 || held_lock_device != authority.lock_device || held_lock.st_ino != authority.lock_inode || current_lock_device != authority.lock_device diff --git a/crates/service_sqlite/src/backup/capture.rs b/crates/service_sqlite/src/backup/capture.rs @@ -945,7 +945,7 @@ fn created_directory_identity( .map_err(|source| backup_source(BackupFailureKind::StagingReplaced, source))?; if !FileType::from_raw_mode(status.st_mode).is_dir() || status.st_uid != geteuid().as_raw() - || u32::from(status.st_mode) & 0o022 != 0 + || crate::native_metadata::mode(status.st_mode) & 0o022 != 0 { return Err(backup_error(BackupFailureKind::StagingReplaced)); } @@ -964,7 +964,7 @@ fn validate_directory_descriptor( ) -> Result<FileIdentity, ServiceSqliteError> { let status = fstat(directory) .map_err(|source| backup_source(BackupFailureKind::InvalidStagingParent, source))?; - let mode = u32::from(status.st_mode) & 0o777; + let mode = crate::native_metadata::mode(status.st_mode) & 0o777; if !FileType::from_raw_mode(status.st_mode).is_dir() || status.st_uid != geteuid().as_raw() || if exact_owner_mode { @@ -982,9 +982,9 @@ fn validate_file_descriptor(file: &File) -> Result<FileIdentity, ServiceSqliteEr let status = fstat(file) .map_err(|source| backup_source(BackupFailureKind::InvalidStagingInventory, source))?; if !FileType::from_raw_mode(status.st_mode).is_file() - || u64::from(status.st_nlink) != 1 + || crate::native_metadata::link_count(status.st_nlink) != 1 || status.st_uid != geteuid().as_raw() - || u32::from(status.st_mode) & 0o777 != 0o600 + || crate::native_metadata::mode(status.st_mode) & 0o777 != 0o600 { return Err(backup_error(BackupFailureKind::InvalidStagingInventory)); } @@ -1067,7 +1067,7 @@ fn current_entry_identity(directory: &File, name: &OsStr) -> Option<FileIdentity fn safe_sidecar_identity(directory: &File, name: &str) -> Option<FileIdentity> { let status = statat(directory, name, AtFlags::SYMLINK_NOFOLLOW).ok()?; if !FileType::from_raw_mode(status.st_mode).is_file() - || u64::from(status.st_nlink) != 1 + || crate::native_metadata::link_count(status.st_nlink) != 1 || status.st_uid != geteuid().as_raw() { return None; @@ -1077,7 +1077,7 @@ fn safe_sidecar_identity(directory: &File, name: &str) -> Option<FileIdentity> { fn identity(status: &rustix::fs::Stat) -> Result<FileIdentity, ServiceSqliteError> { Ok(FileIdentity { - device: u64::try_from(status.st_dev) + device: crate::native_metadata::device(status.st_dev) .map_err(|_| backup_error(BackupFailureKind::StagingReplaced))?, inode: status.st_ino, }) diff --git a/crates/service_sqlite/src/backup/verify.rs b/crates/service_sqlite/src/backup/verify.rs @@ -395,7 +395,7 @@ fn validate_bundle_path(path: &Path) -> Result<(), ServiceSqliteError> { fn validate_directory(directory: &File) -> Result<FileIdentity, ServiceSqliteError> { let status = fstat(directory) .map_err(|source| verification_source(VerificationFailureKind::BundleDirectory, source))?; - let mode = u32::from(status.st_mode) & 0o777; + let mode = crate::native_metadata::mode(status.st_mode) & 0o777; if !FileType::from_raw_mode(status.st_mode).is_dir() || status.st_uid != geteuid().as_raw() || !matches!(mode, 0o500 | 0o700) @@ -409,11 +409,11 @@ fn validate_directory(directory: &File) -> Result<FileIdentity, ServiceSqliteErr fn validate_state(file: &File) -> Result<(FileIdentity, u64), ServiceSqliteError> { let status = fstat(file) .map_err(|source| verification_source(VerificationFailureKind::Inventory, source))?; - let mode = u32::from(status.st_mode) & 0o777; + let mode = crate::native_metadata::mode(status.st_mode) & 0o777; let length = u64::try_from(status.st_size) .map_err(|_| verification_error(VerificationFailureKind::MemberLength))?; if !FileType::from_raw_mode(status.st_mode).is_file() - || u64::from(status.st_nlink) != 1 + || crate::native_metadata::link_count(status.st_nlink) != 1 || status.st_uid != geteuid().as_raw() || !matches!(mode, 0o400 | 0o600) { @@ -428,7 +428,7 @@ fn validate_state(file: &File) -> Result<(FileIdentity, u64), ServiceSqliteError #[cfg(any(target_os = "linux", target_os = "macos"))] fn file_identity(status: &rustix::fs::Stat) -> Result<FileIdentity, ServiceSqliteError> { Ok(FileIdentity { - device: u64::try_from(status.st_dev) + device: crate::native_metadata::device(status.st_dev) .map_err(|_| verification_error(VerificationFailureKind::BindingChanged))?, inode: status.st_ino, }) diff --git a/crates/service_sqlite/src/initialize.rs b/crates/service_sqlite/src/initialize.rs @@ -282,14 +282,14 @@ mod supported { AtFlags::SYMLINK_NOFOLLOW, ) .map_err(|_| InitializationCause::new(InitializationFailureKind::DatabaseReplaced))?; - let device = u64::try_from(status.st_dev).map_err(|_| { + let device = crate::native_metadata::device(status.st_dev).map_err(|_| { InitializationCause::new(InitializationFailureKind::InvalidDatabase) })?; let current = validate_status( FileType::from_raw_mode(status.st_mode).is_file(), - u64::from(status.st_nlink), + crate::native_metadata::link_count(status.st_nlink), status.st_uid, - u32::from(status.st_mode), + crate::native_metadata::mode(status.st_mode), device, status.st_ino, )?; @@ -308,7 +308,7 @@ mod supported { AtFlags::SYMLINK_NOFOLLOW, ) .map_err(|_| InitializationCause::new(InitializationFailureKind::DatabaseReplaced))?; - let device = u64::try_from(status.st_dev).map_err(|_| { + let device = crate::native_metadata::device(status.st_dev).map_err(|_| { InitializationCause::new(InitializationFailureKind::DatabaseReplaced) })?; Ok(FileIdentity { @@ -324,14 +324,14 @@ mod supported { let status = lstat(path).map_err(|_| { InitializationCause::new(InitializationFailureKind::DatabaseReplaced) })?; - let device = u64::try_from(status.st_dev).map_err(|_| { + let device = crate::native_metadata::device(status.st_dev).map_err(|_| { InitializationCause::new(InitializationFailureKind::InvalidDatabase) })?; let current = validate_status( FileType::from_raw_mode(status.st_mode).is_file(), - u64::from(status.st_nlink), + crate::native_metadata::link_count(status.st_nlink), status.st_uid, - u32::from(status.st_mode), + crate::native_metadata::mode(status.st_mode), device, status.st_ino, )?; @@ -399,13 +399,13 @@ mod supported { ) -> Result<FileIdentity, InitializationCause> { let status = fstat(descriptor) .map_err(|_| InitializationCause::new(InitializationFailureKind::InvalidDatabase))?; - let device = u64::try_from(status.st_dev) + let device = crate::native_metadata::device(status.st_dev) .map_err(|_| InitializationCause::new(InitializationFailureKind::InvalidDatabase))?; validate_status( FileType::from_raw_mode(status.st_mode).is_file(), - u64::from(status.st_nlink), + crate::native_metadata::link_count(status.st_nlink), status.st_uid, - u32::from(status.st_mode), + crate::native_metadata::mode(status.st_mode), device, status.st_ino, ) @@ -416,7 +416,7 @@ mod supported { ) -> Result<FileIdentity, InitializationCause> { let status = fstat(descriptor) .map_err(|_| InitializationCause::new(InitializationFailureKind::InvalidDatabase))?; - let device = u64::try_from(status.st_dev) + let device = crate::native_metadata::device(status.st_dev) .map_err(|_| InitializationCause::new(InitializationFailureKind::InvalidDatabase))?; Ok(FileIdentity { device, diff --git a/crates/service_sqlite/src/lib.rs b/crates/service_sqlite/src/lib.rs @@ -13,6 +13,8 @@ mod initialize; mod integrity; mod metadata; mod migration; +#[cfg(any(target_os = "linux", target_os = "macos"))] +mod native_metadata; mod open; mod restore; mod status; diff --git a/crates/service_sqlite/src/native_metadata.rs b/crates/service_sqlite/src/native_metadata.rs @@ -0,0 +1,43 @@ +//! Native filesystem metadata normalization behind portable generic boundaries. + +pub(crate) fn mode<T>(raw: T) -> u32 +where + T: Into<u32>, +{ + raw.into() +} + +pub(crate) fn link_count<T>(raw: T) -> u64 +where + T: Into<u64>, +{ + raw.into() +} + +pub(crate) fn device<T>(raw: T) -> Result<u64, T::Error> +where + T: TryInto<u64>, +{ + raw.try_into() +} + +#[cfg(test)] +mod tests { + use super::{device, link_count, mode}; + + #[test] + fn unsigned_mode_and_link_widths_normalize_without_truncation() { + assert_eq!(mode(0o600_u16), 0o600); + assert_eq!(mode(u32::MAX), u32::MAX); + assert_eq!(link_count(u16::MAX), u64::from(u16::MAX)); + assert_eq!(link_count(u32::MAX), u64::from(u32::MAX)); + assert_eq!(link_count(u64::MAX), u64::MAX); + } + + #[test] + fn signed_and_unsigned_device_widths_remain_checked() { + assert_eq!(device(7_i32), Ok(7)); + assert_eq!(device(u64::MAX), Ok(u64::MAX)); + assert!(device(-1_i32).is_err()); + } +} diff --git a/crates/service_sqlite/src/open.rs b/crates/service_sqlite/src/open.rs @@ -1239,7 +1239,7 @@ impl ReadOnlyInspectionGuard { .map_err(|_| inspection_error(ConnectionFailureKind::InspectionUnavailable))?; if !FileType::from_raw_mode(directory_status.st_mode).is_dir() || directory_status.st_uid != geteuid().as_raw() - || u32::from(directory_status.st_mode) & 0o022 != 0 + || crate::native_metadata::mode(directory_status.st_mode) & 0o022 != 0 { return Err(inspection_error( ConnectionFailureKind::InspectionUnavailable, @@ -1256,9 +1256,9 @@ impl ReadOnlyInspectionGuard { let lock_status = fstat(&lock) .map_err(|_| inspection_error(ConnectionFailureKind::InspectionUnavailable))?; if !FileType::from_raw_mode(lock_status.st_mode).is_file() - || u64::from(lock_status.st_nlink) != 1 + || crate::native_metadata::link_count(lock_status.st_nlink) != 1 || lock_status.st_uid != geteuid().as_raw() - || u32::from(lock_status.st_mode) & 0o777 != 0o600 + || crate::native_metadata::mode(lock_status.st_mode) & 0o777 != 0o600 { return Err(inspection_error( ConnectionFailureKind::InspectionUnavailable, @@ -1302,9 +1302,9 @@ impl ReadOnlyInspectionGuard { ) })?; if !FileType::from_raw_mode(database_status.st_mode).is_file() - || u64::from(database_status.st_nlink) != 1 + || crate::native_metadata::link_count(database_status.st_nlink) != 1 || database_status.st_uid != geteuid().as_raw() - || u32::from(database_status.st_mode) & 0o777 != 0o600 + || crate::native_metadata::mode(database_status.st_mode) & 0o777 != 0o600 { return Err(connection_error( ServiceSqliteErrorKind::Open, @@ -1332,11 +1332,11 @@ impl ReadOnlyInspectionGuard { } Ok(Self { lock: Some(lock), - lock_device: u64::try_from(lock_status.st_dev) + lock_device: crate::native_metadata::device(lock_status.st_dev) .map_err(|_| inspection_error(ConnectionFailureKind::InspectionUnavailable))?, lock_inode: lock_status.st_ino, directory, - directory_device: u64::try_from(directory_status.st_dev) + directory_device: crate::native_metadata::device(directory_status.st_dev) .map_err(|_| inspection_error(ConnectionFailureKind::InspectionUnavailable))?, directory_inode: directory_status.st_ino, _database: database, @@ -1364,16 +1364,16 @@ impl ReadOnlyInspectionGuard { .map_err(|_| inspection_error(ConnectionFailureKind::InspectionUnavailable))?; let held_directory_status = fstat(&self.directory) .map_err(|_| inspection_error(ConnectionFailureKind::InspectionUnavailable))?; - let directory_device = u64::try_from(directory_status.st_dev) + let directory_device = crate::native_metadata::device(directory_status.st_dev) .map_err(|_| inspection_error(ConnectionFailureKind::InspectionUnavailable))?; - let held_directory_device = u64::try_from(held_directory_status.st_dev) + let held_directory_device = crate::native_metadata::device(held_directory_status.st_dev) .map_err(|_| inspection_error(ConnectionFailureKind::InspectionUnavailable))?; if !FileType::from_raw_mode(directory_status.st_mode).is_dir() || directory_status.st_uid != geteuid().as_raw() - || u32::from(directory_status.st_mode) & 0o022 != 0 + || crate::native_metadata::mode(directory_status.st_mode) & 0o022 != 0 || !FileType::from_raw_mode(held_directory_status.st_mode).is_dir() || held_directory_status.st_uid != geteuid().as_raw() - || u32::from(held_directory_status.st_mode) & 0o022 != 0 + || crate::native_metadata::mode(held_directory_status.st_mode) & 0o022 != 0 || directory_device != self.directory_device || directory_status.st_ino != self.directory_inode || held_directory_device != self.directory_device @@ -1399,18 +1399,18 @@ impl ReadOnlyInspectionGuard { .ok_or_else(|| inspection_error(ConnectionFailureKind::InspectionUnavailable))?; let held_lock_status = fstat(held_lock) .map_err(|_| inspection_error(ConnectionFailureKind::InspectionUnavailable))?; - let lock_device = u64::try_from(lock_status.st_dev) + let lock_device = crate::native_metadata::device(lock_status.st_dev) .map_err(|_| inspection_error(ConnectionFailureKind::InspectionUnavailable))?; - let held_lock_device = u64::try_from(held_lock_status.st_dev) + let held_lock_device = crate::native_metadata::device(held_lock_status.st_dev) .map_err(|_| inspection_error(ConnectionFailureKind::InspectionUnavailable))?; if !FileType::from_raw_mode(lock_status.st_mode).is_file() - || u64::from(lock_status.st_nlink) != 1 + || crate::native_metadata::link_count(lock_status.st_nlink) != 1 || lock_status.st_uid != geteuid().as_raw() - || u32::from(lock_status.st_mode) & 0o777 != 0o600 + || crate::native_metadata::mode(lock_status.st_mode) & 0o777 != 0o600 || !FileType::from_raw_mode(held_lock_status.st_mode).is_file() - || u64::from(held_lock_status.st_nlink) != 1 + || crate::native_metadata::link_count(held_lock_status.st_nlink) != 1 || held_lock_status.st_uid != geteuid().as_raw() - || u32::from(held_lock_status.st_mode) & 0o777 != 0o600 + || crate::native_metadata::mode(held_lock_status.st_mode) & 0o777 != 0o600 || lock_device != self.lock_device || lock_status.st_ino != self.lock_inode || held_lock_device != self.lock_device @@ -1505,9 +1505,9 @@ impl DirectoryBinding { ) })?; if !FileType::from_raw_mode(database_status.st_mode).is_file() - || u64::from(database_status.st_nlink) != 1 + || crate::native_metadata::link_count(database_status.st_nlink) != 1 || database_status.st_uid != geteuid().as_raw() - || u32::from(database_status.st_mode) & 0o777 != 0o600 + || crate::native_metadata::mode(database_status.st_mode) & 0o777 != 0o600 { return Err(connection_error( ServiceSqliteErrorKind::Authority, @@ -1522,20 +1522,24 @@ impl DirectoryBinding { ConnectionFailureKind::AuthorityMismatch, ) })?), - directory_device: u64::try_from(directory_status.st_dev).map_err(|_| { - connection_error( - ServiceSqliteErrorKind::Authority, - ConnectionFailureKind::AuthorityMismatch, - ) - })?, + directory_device: crate::native_metadata::device(directory_status.st_dev).map_err( + |_| { + connection_error( + ServiceSqliteErrorKind::Authority, + ConnectionFailureKind::AuthorityMismatch, + ) + }, + )?, directory_inode: directory_status.st_ino, database: Arc::new(File::from(database)), - database_device: u64::try_from(database_status.st_dev).map_err(|_| { - connection_error( - ServiceSqliteErrorKind::Authority, - ConnectionFailureKind::AuthorityMismatch, - ) - })?, + database_device: crate::native_metadata::device(database_status.st_dev).map_err( + |_| { + connection_error( + ServiceSqliteErrorKind::Authority, + ConnectionFailureKind::AuthorityMismatch, + ) + }, + )?, database_inode: database_status.st_ino, }) } @@ -1580,28 +1584,30 @@ impl DirectoryBinding { ConnectionFailureKind::AuthorityMismatch, ) })?; - let directory_device = u64::try_from(directory_status.st_dev).map_err(|_| { - connection_error( - ServiceSqliteErrorKind::Authority, - ConnectionFailureKind::AuthorityMismatch, - ) - })?; - let held_directory_device = u64::try_from(held_directory_status.st_dev).map_err(|_| { - connection_error( - ServiceSqliteErrorKind::Authority, - ConnectionFailureKind::AuthorityMismatch, - ) - })?; + let directory_device = + crate::native_metadata::device(directory_status.st_dev).map_err(|_| { + connection_error( + ServiceSqliteErrorKind::Authority, + ConnectionFailureKind::AuthorityMismatch, + ) + })?; + let held_directory_device = crate::native_metadata::device(held_directory_status.st_dev) + .map_err(|_| { + connection_error( + ServiceSqliteErrorKind::Authority, + ConnectionFailureKind::AuthorityMismatch, + ) + })?; if directory_device != self.directory_device || directory_status.st_ino != self.directory_inode || held_directory_device != self.directory_device || held_directory_status.st_ino != self.directory_inode || !FileType::from_raw_mode(directory_status.st_mode).is_dir() || directory_status.st_uid != geteuid().as_raw() - || u32::from(directory_status.st_mode) & 0o022 != 0 + || crate::native_metadata::mode(directory_status.st_mode) & 0o022 != 0 || !FileType::from_raw_mode(held_directory_status.st_mode).is_dir() || held_directory_status.st_uid != geteuid().as_raw() - || u32::from(held_directory_status.st_mode) & 0o022 != 0 + || crate::native_metadata::mode(held_directory_status.st_mode) & 0o022 != 0 { return Err(connection_error( ServiceSqliteErrorKind::Authority, @@ -1633,26 +1639,28 @@ impl DirectoryBinding { ConnectionFailureKind::AuthorityMismatch, ) })?; - let database_device = u64::try_from(database_status.st_dev).map_err(|_| { - connection_error( - ServiceSqliteErrorKind::Authority, - ConnectionFailureKind::AuthorityMismatch, - ) - })?; - let held_database_device = u64::try_from(held_database_status.st_dev).map_err(|_| { - connection_error( - ServiceSqliteErrorKind::Authority, - ConnectionFailureKind::AuthorityMismatch, - ) - })?; + let database_device = + crate::native_metadata::device(database_status.st_dev).map_err(|_| { + connection_error( + ServiceSqliteErrorKind::Authority, + ConnectionFailureKind::AuthorityMismatch, + ) + })?; + let held_database_device = crate::native_metadata::device(held_database_status.st_dev) + .map_err(|_| { + connection_error( + ServiceSqliteErrorKind::Authority, + ConnectionFailureKind::AuthorityMismatch, + ) + })?; if !FileType::from_raw_mode(database_status.st_mode).is_file() - || u64::from(database_status.st_nlink) != 1 + || crate::native_metadata::link_count(database_status.st_nlink) != 1 || database_status.st_uid != geteuid().as_raw() - || u32::from(database_status.st_mode) & 0o777 != 0o600 + || crate::native_metadata::mode(database_status.st_mode) & 0o777 != 0o600 || !FileType::from_raw_mode(held_database_status.st_mode).is_file() - || u64::from(held_database_status.st_nlink) != 1 + || crate::native_metadata::link_count(held_database_status.st_nlink) != 1 || held_database_status.st_uid != geteuid().as_raw() - || u32::from(held_database_status.st_mode) & 0o777 != 0o600 + || crate::native_metadata::mode(held_database_status.st_mode) & 0o777 != 0o600 || database_device != self.database_device || database_status.st_ino != self.database_inode || held_database_device != self.database_device diff --git a/crates/service_sqlite/src/restore/finalize.rs b/crates/service_sqlite/src/restore/finalize.rs @@ -362,12 +362,12 @@ fn verify_named_artifact( validate_status(&held_status, Some(expected.byte_length()))?; validate_status(&current_status, Some(expected.byte_length()))?; let held_identity = ( - u64::try_from(held_status.st_dev) + crate::native_metadata::device(held_status.st_dev) .map_err(|_| finalize_error(FinalizeFailureKind::Artifact))?, held_status.st_ino, ); let current_identity = ( - u64::try_from(current_status.st_dev) + crate::native_metadata::device(current_status.st_dev) .map_err(|_| finalize_error(FinalizeFailureKind::Artifact))?, current_status.st_ino, ); @@ -388,9 +388,9 @@ fn validate_status( let length = u64::try_from(status.st_size).map_err(|_| finalize_error(FinalizeFailureKind::Artifact))?; if !FileType::from_raw_mode(status.st_mode).is_file() - || u64::from(status.st_nlink) != 1 + || crate::native_metadata::link_count(status.st_nlink) != 1 || status.st_uid != geteuid().as_raw() - || u32::from(status.st_mode) & 0o777 != 0o600 + || crate::native_metadata::mode(status.st_mode) & 0o777 != 0o600 || length == 0 || length > i64::MAX as u64 || expected_length.is_some_and(|expected| length != expected) diff --git a/crates/service_sqlite/src/restore/marker.rs b/crates/service_sqlite/src/restore/marker.rs @@ -1316,7 +1316,7 @@ mod store { let status = fstat(file).map_err(|_| StoreFailure::Directory)?; if !FileType::from_raw_mode(status.st_mode).is_dir() || status.st_uid != geteuid().as_raw() - || u32::from(status.st_mode) & 0o022 != 0 + || crate::native_metadata::mode(status.st_mode) & 0o022 != 0 { return Err(StoreFailure::Directory); } @@ -1387,9 +1387,9 @@ mod store { fn file_identity(file: &File) -> Result<FileIdentity, StoreFailure> { let status = fstat(file).map_err(|_| StoreFailure::Marker)?; if !FileType::from_raw_mode(status.st_mode).is_file() - || u64::from(status.st_nlink) != 1 + || crate::native_metadata::link_count(status.st_nlink) != 1 || status.st_uid != geteuid().as_raw() - || u32::from(status.st_mode) & 0o777 != 0o600 + || crate::native_metadata::mode(status.st_mode) & 0o777 != 0o600 { return Err(StoreFailure::Marker); } diff --git a/crates/service_sqlite/src/restore/recover.rs b/crates/service_sqlite/src/restore/recover.rs @@ -331,8 +331,8 @@ fn artifact_has_identity( ) -> Result<bool, ServiceSqliteError> { let status = fstat(file).map_err(|source| recovery_source(RecoveryFailureKind::Artifact, source))?; - let device = - u64::try_from(status.st_dev).map_err(|_| recovery_error(RecoveryFailureKind::Artifact))?; + let device = crate::native_metadata::device(status.st_dev) + .map_err(|_| recovery_error(RecoveryFailureKind::Artifact))?; Ok((device, status.st_ino) == (expected.device(), expected.inode())) } @@ -343,14 +343,14 @@ fn verify_artifact( ) -> Result<(), ServiceSqliteError> { let status = fstat(file).map_err(|source| recovery_source(RecoveryFailureKind::Artifact, source))?; - let device = - u64::try_from(status.st_dev).map_err(|_| recovery_error(RecoveryFailureKind::Artifact))?; + let device = crate::native_metadata::device(status.st_dev) + .map_err(|_| recovery_error(RecoveryFailureKind::Artifact))?; let length = u64::try_from(status.st_size).map_err(|_| recovery_error(RecoveryFailureKind::Artifact))?; if !FileType::from_raw_mode(status.st_mode).is_file() - || u64::from(status.st_nlink) != 1 + || crate::native_metadata::link_count(status.st_nlink) != 1 || status.st_uid != geteuid().as_raw() - || u32::from(status.st_mode) & 0o777 != 0o600 + || crate::native_metadata::mode(status.st_mode) & 0o777 != 0o600 || (device, status.st_ino) != (expected.device(), expected.inode()) || length != expected.byte_length() || length == 0 @@ -1016,7 +1016,7 @@ mod tests { let file = File::open(path).expect("open artifact"); let status = fstat(&file).expect("artifact status"); RestoreArtifactExpectation::new( - u64::try_from(status.st_dev).expect("device"), + crate::native_metadata::device(status.st_dev).expect("device"), status.st_ino, u64::try_from(status.st_size).expect("length"), hash_exact( diff --git a/crates/service_sqlite/src/restore/stage.rs b/crates/service_sqlite/src/restore/stage.rs @@ -664,7 +664,7 @@ fn directory_identity(directory: &File) -> Result<FileIdentity, ServiceSqliteErr fstat(directory).map_err(|source| restore_source(RestoreFailureKind::Layout, source))?; if !FileType::from_raw_mode(status.st_mode).is_dir() || status.st_uid != geteuid().as_raw() - || u32::from(status.st_mode) & 0o022 != 0 + || crate::native_metadata::mode(status.st_mode) & 0o022 != 0 { return Err(restore_error(RestoreFailureKind::Layout)); } @@ -682,7 +682,7 @@ fn stage_identity(staged: &File) -> Result<FileIdentity, ServiceSqliteError> { #[cfg(any(target_os = "linux", target_os = "macos"))] fn status_identity(status: &rustix::fs::Stat) -> Result<FileIdentity, ServiceSqliteError> { Ok(FileIdentity { - device: u64::try_from(status.st_dev) + device: crate::native_metadata::device(status.st_dev) .map_err(|_| restore_error(RestoreFailureKind::StagedChanged))?, inode: status.st_ino, }) @@ -801,9 +801,9 @@ fn validate_closed_live( let status = fstat(&live).map_err(|source| restore_source(RestoreFailureKind::LiveState, source))?; if !FileType::from_raw_mode(status.st_mode).is_file() - || u64::from(status.st_nlink) != 1 + || crate::native_metadata::link_count(status.st_nlink) != 1 || status.st_uid != geteuid().as_raw() - || u32::from(status.st_mode) & 0o777 != 0o600 + || crate::native_metadata::mode(status.st_mode) & 0o777 != 0o600 { return Err(restore_error(RestoreFailureKind::LiveState)); } @@ -815,7 +815,8 @@ fn validate_closed_live( let live = File::from(live); let digest = hash_exact(&live, length)?; let artifact = RestoreArtifactExpectation::new( - u64::try_from(status.st_dev).map_err(|_| restore_error(RestoreFailureKind::LiveState))?, + crate::native_metadata::device(status.st_dev) + .map_err(|_| restore_error(RestoreFailureKind::LiveState))?, status.st_ino, length, digest, @@ -848,14 +849,14 @@ fn validate_live_binding( .map_err(|source| restore_source(RestoreFailureKind::LiveState, source))?; let status = fstat(&current).map_err(|source| restore_source(RestoreFailureKind::LiveState, source))?; - let device = - u64::try_from(status.st_dev).map_err(|_| restore_error(RestoreFailureKind::LiveState))?; + let device = crate::native_metadata::device(status.st_dev) + .map_err(|_| restore_error(RestoreFailureKind::LiveState))?; let length = u64::try_from(status.st_size).map_err(|_| restore_error(RestoreFailureKind::LiveState))?; if !FileType::from_raw_mode(status.st_mode).is_file() - || u64::from(status.st_nlink) != 1 + || crate::native_metadata::link_count(status.st_nlink) != 1 || status.st_uid != geteuid().as_raw() - || u32::from(status.st_mode) & 0o777 != 0o600 + || crate::native_metadata::mode(status.st_mode) & 0o777 != 0o600 || (device, status.st_ino) != (expected.device(), expected.inode()) || length != expected.byte_length() { @@ -898,9 +899,9 @@ fn validate_stage_status( let length = u64::try_from(status.st_size) .map_err(|_| restore_error(RestoreFailureKind::StagedChanged))?; if !FileType::from_raw_mode(status.st_mode).is_file() - || u64::from(status.st_nlink) != 1 + || crate::native_metadata::link_count(status.st_nlink) != 1 || status.st_uid != geteuid().as_raw() - || u32::from(status.st_mode) & 0o777 != 0o600 + || crate::native_metadata::mode(status.st_mode) & 0o777 != 0o600 || expected_length.is_some_and(|expected| length != expected) { return Err(restore_error(RestoreFailureKind::StagedChanged)); diff --git a/crates/service_sqlite/src/status/disk.rs b/crates/service_sqlite/src/status/disk.rs @@ -230,7 +230,7 @@ fn validate_directory_status( if !FileType::from_raw_mode(status.st_mode).is_dir() || status.st_uid != geteuid().as_raw() - || u32::from(status.st_mode) & 0o022 != 0 + || crate::native_metadata::mode(status.st_mode) & 0o022 != 0 { return Err(StateFilesystemCapacityError::MeasurementUnavailable); } diff --git a/crates/service_sqlite/tests/package_boundary.rs b/crates/service_sqlite/tests/package_boundary.rs @@ -22,6 +22,7 @@ const INTEGRITY_CATALOG_SOURCE: &str = include_str!("../src/integrity/catalog.rs const INTEGRITY_INSPECTION_SOURCE: &str = include_str!("../src/integrity/inspection.rs"); const METADATA_SOURCE: &str = include_str!("../src/metadata.rs"); const MIGRATION_SOURCE: &str = include_str!("../src/migration.rs"); +const NATIVE_METADATA_SOURCE: &str = include_str!("../src/native_metadata.rs"); const OPEN_SOURCE: &str = include_str!("../src/open.rs"); const RESTORE_MARKER_SOURCE: &str = include_str!("../src/restore/marker.rs"); const RESTORE_FINALIZE_SOURCE: &str = include_str!("../src/restore/finalize.rs"); @@ -122,6 +123,7 @@ fn service_sqlite_is_unpublished_lint_governed_and_dependency_bounded() { "integrity", "metadata", "migration", + "native_metadata", "open", "restore", "status", @@ -529,7 +531,7 @@ fn service_sqlite_is_unpublished_lint_governed_and_dependency_bounded() { "fstatvfs(&held)", "capacity.f_bavail", "capacity.f_frsize", - "u32::from(status.st_mode) & 0o022", + "crate::native_metadata::mode(status.st_mode) & 0o022", "UnsupportedPlatform", ] { assert!( @@ -537,6 +539,26 @@ fn service_sqlite_is_unpublished_lint_governed_and_dependency_bounded() { "Step 071 disk inspection source is missing `{required}`" ); } + + for required in [ + "pub(crate) fn mode<T>", + "T: Into<u32>", + "pub(crate) fn link_count<T>", + "T: Into<u64>", + "pub(crate) fn device<T>", + "T: TryInto<u64>", + ] { + assert!( + NATIVE_METADATA_SOURCE.contains(required), + "native metadata normalization is missing `{required}`" + ); + } + for forbidden in ["pub fn mode", "pub fn link_count", "pub fn device"] { + assert!( + !NATIVE_METADATA_SOURCE.contains(forbidden), + "native metadata normalization exposes `{forbidden}`" + ); + } for forbidden in [ "ServiceSqliteHost", "readyz", @@ -1504,7 +1526,7 @@ fn service_sqlite_is_unpublished_lint_governed_and_dependency_bounded() { "directory_device", "WAL_FILE_NAME", "SHARED_MEMORY_FILE_NAME", - "u32::from(directory_status.st_mode) & 0o022", + "crate::native_metadata::mode(directory_status.st_mode) & 0o022", ] { assert!( OPEN_SOURCE.contains(required),