From 02c55f1480dd8efcf8f33abc583476d5adde3d1b Mon Sep 17 00:00:00 2001 From: edef Date: Sun, 31 Jul 2022 17:33:01 +0000 Subject: ripple/minitrace/syscall_abi/device: init dev_t, but non-nullable and with a proper Rust API. Change-Id: I3d968b25f59b6e1a35c88f94bd0f135873b6dc2b --- ripple/minitrace/src/syscall_abi/device.rs | 95 ++++++++++++++++++++++++++++++ ripple/minitrace/src/syscall_abi/mod.rs | 8 ++- 2 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 ripple/minitrace/src/syscall_abi/device.rs (limited to 'ripple') diff --git a/ripple/minitrace/src/syscall_abi/device.rs b/ripple/minitrace/src/syscall_abi/device.rs new file mode 100644 index 0000000..743a02a --- /dev/null +++ b/ripple/minitrace/src/syscall_abi/device.rs @@ -0,0 +1,95 @@ +// SPDX-FileCopyrightText: edef +// SPDX-License-Identifier: OSL-3.0 + +use std::{ + fmt::{self, Debug}, + num::NonZeroU64, +}; + +/// `Device` represents a non-zero `libc::dev_t`. +/// `Option` has identical representation to `libc::dev_t`. +#[repr(transparent)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub(crate) struct Device(NonZeroU64); + +impl Debug for Device { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Device({}, {})", self.major(), self.minor()) + } +} + +impl Device { + pub(crate) fn new(major: u32, minor: u32) -> Device { + Self::checked_new(major, minor).expect("zero major *and* minor device number") + } + + pub(crate) fn checked_new(major: u32, minor: u32) -> Option { + let major = major as u64; + let minor = minor as u64; + + let dev = 0 + | (major & 0x00000fff) << 8 + | (major & 0xfffff000) << 32 + | (minor & 0x000000ff) << 0 + | (minor & 0xffffff00) << 12; + + NonZeroU64::new(dev).map(Device) + } + + pub(crate) fn dev(&self) -> u64 { + self.0.into() + } + + pub(crate) fn major(&self) -> u32 { + let mut major = 0; + major |= (self.dev() & 0x00000000000fff00) >> 8; + major |= (self.dev() & 0xfffff00000000000) >> 32; + major as u32 + } + + pub(crate) fn minor(&self) -> u32 { + let mut minor = 0; + minor |= (self.dev() & 0x00000000000000ff) >> 0; + minor |= (self.dev() & 0x00000ffffff00000) >> 12; + minor as u32 + } +} + +#[cfg(test)] +mod test { + use {super::Device, nix::libc, std::mem}; + + #[test] + #[should_panic = "zero major *and* minor device number"] + fn no_zero() { + Device::new(0, 0); + } + + #[test] + fn none_repr() { + unsafe { + let dev: libc::dev_t = mem::transmute(None::); + assert_eq!(dev, 0); + } + } + + const GOLDEN: &[((u32, u32), libc::dev_t)] = &[ + ((0xaaaaa555, 0xaaaaaa55), 0xaaaaaaaaaaa55555), + ((0x55555aaa, 0x555555aa), 0x55555555555aaaaa), + ((0xaaaaaaaa, 0x55555555), 0xaaaaa555555aaa55), + ((0x12345678, 0xabcdef42), 0x12345abcdef67842), + ]; + + #[test] + fn golden() { + for &golden @ ((major, minor), dev) in GOLDEN { + let libc_dev = unsafe { libc::makedev(major, minor) }; + if dev != libc_dev { + panic!("broken test: reference data ({dev:#016x}) does not match libc ({libc_dev:#016x})"); + } + + let d = Device::new(major, minor); + assert_eq!(golden, ((d.major(), d.minor()), d.dev())); + } + } +} diff --git a/ripple/minitrace/src/syscall_abi/mod.rs b/ripple/minitrace/src/syscall_abi/mod.rs index e050711..31fd2e7 100644 --- a/ripple/minitrace/src/syscall_abi/mod.rs +++ b/ripple/minitrace/src/syscall_abi/mod.rs @@ -10,10 +10,14 @@ use { }, }; -pub(crate) use arg::{ProcessSyscallArg, SyscallArg}; -pub(crate) use fd::{DirFd, FileDesc}; +pub(crate) use { + arg::{ProcessSyscallArg, SyscallArg}, + device::Device, + fd::{DirFd, FileDesc}, +}; mod arg; +mod device; mod fd; pub mod macros; -- cgit 1.4.1