Skip to content

Commit

Permalink
all: use anyhow
Browse files Browse the repository at this point in the history
I was getting sick of typing std::io::Result<()> all the time.  Also:
some guy on users.rust-lang.org says that it's cool, even in libraries.

This is a very literal port with very few features actually used.
  • Loading branch information
allisonkarlitskaya committed Oct 5, 2024
1 parent 9f8c273 commit da5422e
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 42 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ version = "0.1.0"
edition = "2021"

[dependencies]
anyhow = { version = "1.0.89", features = ["backtrace"] }
clap = { version = "4.5.19", features = ["derive"] }
hex = "0.4.3"
rand = "0.8.5"
Expand Down
21 changes: 12 additions & 9 deletions src/bin/mount.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
use std::os::fd::{
OwnedFd,
BorrowedFd,
AsFd,
AsRawFd
};

use anyhow::Result;
use rustix::mount::{
FsMountFlags,
FsOpenFlags,
Expand All @@ -11,12 +19,7 @@ use rustix::mount::{
move_mount,
unmount,
};
use std::os::fd::{
OwnedFd,
BorrowedFd,
AsFd,
AsRawFd
};

use composefs_experiments::{
fsverity,
tmpdir,
Expand All @@ -27,7 +30,7 @@ struct FsHandle {
}

impl FsHandle {
pub fn open(name: &str) -> std::io::Result<FsHandle> {
pub fn open(name: &str) -> Result<FsHandle> {
Ok(FsHandle { fd: fsopen(name, FsOpenFlags::FSOPEN_CLOEXEC)? })
}
}
Expand Down Expand Up @@ -56,7 +59,7 @@ struct TmpMount {
}

impl TmpMount {
pub fn mount(fs: BorrowedFd) -> std::io::Result<TmpMount> {
pub fn mount(fs: BorrowedFd) -> Result<TmpMount> {
let tmp = tmpdir::TempDir::new()?;
let mnt = fsmount(fs, FsMountFlags::FSMOUNT_CLOEXEC, MountAttrFlags::empty())?;
move_mount(mnt.as_fd(), "", rustix::fs::CWD, &tmp.path, MoveMountFlags::MOVE_MOUNT_F_EMPTY_PATH)?;
Expand Down Expand Up @@ -95,7 +98,7 @@ impl<'a> MountOptions<'a> {
self.digest = Some(digest);
}

fn mount(self, mountpoint: &str) -> std::io::Result<()> {
fn mount(self, mountpoint: &str) -> Result<()> {
let image = std::fs::File::open(self.image)?;

if let Some(expected) = self.digest {
Expand Down
4 changes: 3 additions & 1 deletion src/bin/splitstream.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use anyhow::Result;

use composefs_experiments::{
fsverity::Sha256HashValue,
tar::split,
Expand All @@ -11,7 +13,7 @@ fn main() {
split(
&mut std::io::stdin(),
&mut std::io::stdout(),
|data: &[u8]| -> std::io::Result<Sha256HashValue> {
|data: &[u8]| -> Result<Sha256HashValue> {
repo.ensure_object(&data)
}
).expect("split");
Expand Down
11 changes: 7 additions & 4 deletions src/fsverity/ioctl.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use super::FsVerityHashValue;
use std::os::fd::AsFd;

use anyhow::Result;
use rustix::ioctl;

use super::FsVerityHashValue;

// See /usr/include/linux/fsverity.h
#[repr(C)]
pub struct FsVerityEnableArg {
Expand All @@ -19,7 +22,7 @@ pub struct FsVerityEnableArg {
// #define FS_IOC_ENABLE_VERITY _IOW('f', 133, struct fsverity_enable_arg)
type FsIocEnableVerity = ioctl::WriteOpcode<b'f', 133, FsVerityEnableArg>;

pub fn fs_ioc_enable_verity<F: AsFd, H: FsVerityHashValue>(fd: F) -> std::io::Result<()> {
pub fn fs_ioc_enable_verity<F: AsFd, H: FsVerityHashValue>(fd: F) -> Result<()> {
unsafe {
ioctl::ioctl(fd, ioctl::Setter::<FsIocEnableVerity, FsVerityEnableArg>::new(FsVerityEnableArg {
version: 1,
Expand Down Expand Up @@ -47,7 +50,7 @@ pub struct FsVerityDigest<F> {
// #define FS_IOC_MEASURE_VERITY _IORW('f', 134, struct fsverity_digest)
type FsIocMeasureVerity = ioctl::ReadWriteOpcode<b'f', 134, FsVerityDigest<()>>;

pub fn fs_ioc_measure_verity<F: AsFd, H: FsVerityHashValue>(fd: F) -> std::io::Result<H> {
pub fn fs_ioc_measure_verity<F: AsFd, H: FsVerityHashValue>(fd: F) -> Result<H> {
let digest_size = std::mem::size_of::<H>() as u16;
let digest_algorithm = H::ALGORITHM as u16;

Expand All @@ -58,7 +61,7 @@ pub fn fs_ioc_measure_verity<F: AsFd, H: FsVerityHashValue>(fd: F) -> std::io::R
}

if digest.digest_algorithm != digest_algorithm || digest.digest_size != digest_size {
Err(std::io::Error::from(std::io::ErrorKind::InvalidData))
Err(std::io::Error::from(std::io::ErrorKind::InvalidData))?
} else {
Ok(digest.digest)
}
Expand Down
27 changes: 14 additions & 13 deletions src/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::path::{
PathBuf,
};

use anyhow::Result;
use rustix::fs::{
Access,
AtFlags,
Expand Down Expand Up @@ -51,30 +52,30 @@ impl Drop for Repository {
}

impl Repository {
pub fn open_fd(repository: OwnedFd) -> std::io::Result<Repository> {
pub fn open_fd(repository: OwnedFd) -> Result<Repository> {
flock(&repository, FlockOperation::LockShared)?;
Ok(Repository { repository })
}

pub fn open_path<P: rustix::path::Arg>(path: P) -> std::io::Result<Repository> {
pub fn open_path<P: rustix::path::Arg>(path: P) -> Result<Repository> {
// O_PATH isn't enough because flock()
Repository::open_fd(open(path, OFlags::RDONLY, Mode::empty())?)
}

pub fn open_default() -> std::io::Result<Repository> {
pub fn open_default() -> Result<Repository> {
let home = PathBuf::from(std::env::var("HOME").expect("$HOME must be set"));
Repository::open_path(home.join(".var/lib/composefs"))
}

fn ensure_parent<P: AsRef<Path>>(&self, path: P) -> std::io::Result<()> {
fn ensure_parent<P: AsRef<Path>>(&self, path: P) -> Result<()> {
match path.as_ref().parent() {
None => Ok(()),
Some(path) if path == Path::new("") => Ok(()),
Some(parent) => self.ensure_dir(parent)
}
}

fn ensure_dir<P: AsRef<Path>>(&self, dir: P) -> std::io::Result<()> {
fn ensure_dir<P: AsRef<Path>>(&self, dir: P) -> Result<()> {
self.ensure_parent(&dir)?;

match mkdirat(&self.repository, dir.as_ref(), 0o777.into()) {
Expand All @@ -83,7 +84,7 @@ impl Repository {
Err(err) => Err(err.into())
}
}
pub fn ensure_object(&self, data: &[u8]) -> std::io::Result<Sha256HashValue> {
pub fn ensure_object(&self, data: &[u8]) -> Result<Sha256HashValue> {
let digest = FsVerityHasher::hash(data);
let dir = PathBuf::from(format!("objects/{:02x}", digest[0]));
let file = dir.join(hex::encode(&digest[1..]));
Expand Down Expand Up @@ -118,17 +119,17 @@ impl Repository {
Ok(digest)
}

pub fn merge_splitstream<W: Write>(&self, name: &str, stream: &mut W) -> std::io::Result<()> {
pub fn merge_splitstream<W: Write>(&self, name: &str, stream: &mut W) -> Result<()> {
Ok(())
}

pub fn import_tar<R: Read>(&self, name: &str, tar_stream: &mut R) -> std::io::Result<()> {
pub fn import_tar<R: Read>(&self, name: &str, tar_stream: &mut R) -> Result<()> {
let mut split_stream = zstd::stream::write::Encoder::new(vec![], 0)?;

tar::split(
tar_stream,
&mut split_stream,
|data: &[u8]| -> std::io::Result<Sha256HashValue> {
|data: &[u8]| -> Result<Sha256HashValue> {
self.ensure_object(data)
})?;

Expand All @@ -138,7 +139,7 @@ impl Repository {

fn link_ref(
&self, name: &str, category: &str, object_id: Sha256HashValue
) -> std::io::Result<()> {
) -> Result<()> {
let object_path = format!("objects/{:02x}/{}", object_id[0], hex::encode(&object_id[1..]));
let category_path = format!("{}/{}", category, hex::encode(&object_id));
let ref_path = format!("refs/{}", name);
Expand All @@ -148,7 +149,7 @@ impl Repository {
Ok(())
}

fn symlink<P: AsRef<Path>>(&self, name: P, target: &str) -> std::io::Result<()> {
fn symlink<P: AsRef<Path>>(&self, name: P, target: &str) -> Result<()> {
let name = name.as_ref();
let parent = name.parent()
.expect("make_link() called for file directly in repo top-level");
Expand All @@ -163,15 +164,15 @@ impl Repository {
Ok(symlinkat(target_path, &self.repository, name)?)
}

pub fn gc(&self) -> std::io::Result<()> {
pub fn gc(&self) -> Result<()> {
flock(&self.repository, FlockOperation::LockExclusive)?;

// TODO: GC

Ok(flock(&self.repository, FlockOperation::LockShared)?) // XXX: finally { } ?
}

pub fn fsck(&self) -> std::io::Result<()> {
pub fn fsck(&self) -> Result<()> {
Ok(())
}
}
13 changes: 8 additions & 5 deletions src/splitstream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
*/

use std::io::Write;

use anyhow::Result;

use crate::fsverity::Sha256HashValue;

// utility class to help write splitstreams
Expand All @@ -42,13 +45,13 @@ impl<'w, W: Write> SplitStreamWriter<'w, W> {
SplitStreamWriter { inline_content: vec![], writer }
}

fn write_fragment(writer: &mut W, size: usize, data: &[u8]) -> std::io::Result<()> {
fn write_fragment(writer: &mut W, size: usize, data: &[u8]) -> Result<()> {
writer.write_all(&(size as u64).to_le_bytes())?;
writer.write_all(data)
Ok(writer.write_all(data)?)
}

/// flush any buffered inline data, taking new_value as the new value of the buffer
fn flush_inline(&mut self, new_value: Vec<u8>) -> std::io::Result<()> {
fn flush_inline(&mut self, new_value: Vec<u8>) -> Result<()> {
if !self.inline_content.is_empty() {
SplitStreamWriter::write_fragment(self.writer, self.inline_content.len(), &self.inline_content)?;
self.inline_content = new_value;
Expand All @@ -65,15 +68,15 @@ impl<'w, W: Write> SplitStreamWriter<'w, W> {
/// write a reference to external data to the stream. If the external data had padding in the
/// stream which is not stored in the object then pass it here as well and it will be stored
/// inline after the reference.
pub fn write_reference(&mut self, reference: Sha256HashValue, padding: Vec<u8>) -> std::io::Result<()> {
pub fn write_reference(&mut self, reference: Sha256HashValue, padding: Vec<u8>) -> Result<()> {
// Flush the inline data before we store the external reference. Any padding from the
// external data becomes the start of a new inline block.
self.flush_inline(padding)?;

SplitStreamWriter::write_fragment(self.writer, 0, &reference)
}

pub fn done(&mut self) -> std::io::Result<()> {
pub fn done(&mut self) -> Result<()> {
self.flush_inline(vec![])
}
}
Expand Down
16 changes: 10 additions & 6 deletions src/tar.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::io::{Read, Write};

use anyhow::Result;

use crate::fsverity::Sha256HashValue;
use crate::splitstream::SplitStreamWriter;

Expand All @@ -8,23 +11,24 @@ struct TarHeader {

impl TarHeader {
// we can't use Read::read_exact() because we need to be able to detect EOF
fn read<R: Read>(reader: &mut R) -> std::io::Result<Option<TarHeader>> {
fn read<R: Read>(reader: &mut R) -> Result<Option<TarHeader>> {
let mut header = TarHeader { data: [0u8; 512] };
let mut todo: &mut [u8] = &mut header.data;

while !todo.is_empty() {
match reader.read(todo) {
Ok(0) => match todo.len() {
512 => return Ok(None),
_ => return Err(std::io::ErrorKind::UnexpectedEof.into()),
512 => return Ok(None), // clean EOF
_ => Err(std::io::Error::from(std::io::ErrorKind::UnexpectedEof))?
},
Ok(n) => {
todo = &mut todo[n..];
}
Err(e) if e.kind() == std::io::ErrorKind::Interrupted => {
continue;
}
Err(e) => {
return Err(e);
Err(e)?;
}
}
}
Expand Down Expand Up @@ -72,11 +76,11 @@ impl TarHeader {
/// Splits the tar file from tar_stream into a Split Stream. The store_data function is
/// responsible for ensuring that "external data" is in the composefs repository and returns the
/// fsverity hash value of that data.
pub fn split<R: Read, W: Write, F: FnMut(&[u8]) -> std::io::Result<Sha256HashValue>>(
pub fn split<R: Read, W: Write, F: FnMut(&[u8]) -> Result<Sha256HashValue>>(
tar_stream: &mut R,
split_stream: &mut W,
mut store_data: F,
) -> std::io::Result<()> {
) -> Result<()> {
let mut writer = SplitStreamWriter::new(split_stream);

while let Some(header) = TarHeader::read(tar_stream)? {
Expand Down
13 changes: 9 additions & 4 deletions src/tmpdir.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
use rand::distributions::{Alphanumeric, DistString};
use std::path::PathBuf;

use anyhow::{
Result,
bail,
};
use rand::distributions::{Alphanumeric, DistString};

pub struct TempDir {
pub path: PathBuf,
}

impl TempDir {
pub fn new() -> std::io::Result<TempDir>{
pub fn new() -> Result<TempDir>{
let tmp = PathBuf::from("/tmp");

for _ in 0 .. 26*26*26 { // this is how many times glibc tries
Expand All @@ -15,11 +20,11 @@ impl TempDir {
match std::fs::create_dir(&path) {
Ok(()) => return Ok(TempDir { path }),
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => continue,
Err(e) => return Err(e)
Err(e) => Err(e)?
}
}

Err(std::io::Error::from(std::io::ErrorKind::AlreadyExists))
bail!("Failed to find free name for temporary directory");
}
}

Expand Down

0 comments on commit da5422e

Please sign in to comment.