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:
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(¤t_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(¤t_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(¤t_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(¤t).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),