summaryrefslogtreecommitdiff
path: root/rust-src/bch_bindgen/src
diff options
context:
space:
mode:
Diffstat (limited to 'rust-src/bch_bindgen/src')
-rw-r--r--rust-src/bch_bindgen/src/btree.rs80
-rw-r--r--rust-src/bch_bindgen/src/errcode.rs40
-rw-r--r--rust-src/bch_bindgen/src/fs.rs30
-rw-r--r--rust-src/bch_bindgen/src/lib.rs172
-rw-r--r--rust-src/bch_bindgen/src/libbcachefs_wrapper.h1
-rw-r--r--rust-src/bch_bindgen/src/rs.rs10
6 files changed, 324 insertions, 9 deletions
diff --git a/rust-src/bch_bindgen/src/btree.rs b/rust-src/bch_bindgen/src/btree.rs
new file mode 100644
index 00000000..da9dbca6
--- /dev/null
+++ b/rust-src/bch_bindgen/src/btree.rs
@@ -0,0 +1,80 @@
+use crate::SPOS_MAX;
+use crate::c;
+use crate::fs::Fs;
+use crate::errcode::{bch_errcode, errptr_to_result_c};
+use std::mem::MaybeUninit;
+use std::ptr;
+
+pub struct BtreeTrans {
+ raw: c::btree_trans,
+}
+
+impl BtreeTrans {
+ pub fn new<'a>(fs: &'a Fs) -> BtreeTrans {
+ unsafe {
+ let mut trans: MaybeUninit<BtreeTrans> = MaybeUninit::uninit();
+
+ c::__bch2_trans_init(&mut (*trans.as_mut_ptr()).raw, fs.raw, 0);
+ trans.assume_init()
+ }
+ }
+}
+
+impl Drop for BtreeTrans {
+ fn drop(&mut self) {
+ unsafe { c::bch2_trans_exit(&mut self.raw) }
+ }
+}
+
+pub struct BtreeIter {
+ raw: c::btree_iter,
+}
+
+impl BtreeIter {
+ pub fn new<'a>(trans: &'a BtreeTrans, btree: c::btree_id, pos: c::bpos, flags: u32) -> BtreeIter {
+ unsafe {
+ let mut iter: MaybeUninit<BtreeIter> = MaybeUninit::uninit();
+
+ c::bch2_trans_iter_init_outlined(
+ ptr::addr_of!(trans.raw).cast_mut(),
+ &mut (*iter.as_mut_ptr()).raw,
+ btree as u32,
+ pos,
+ flags);
+ iter.assume_init()
+ }
+ }
+
+ pub fn peek_upto(&mut self, end: c::bpos) -> Result<c::bkey_s_c, bch_errcode> {
+ unsafe {
+ let k = c::bch2_btree_iter_peek_upto(&mut self.raw, end);
+ errptr_to_result_c(k.k).map(|_| k)
+ }
+ }
+
+ pub fn peek(&mut self) -> Result<c::bkey_s_c, bch_errcode> {
+ self.peek_upto(SPOS_MAX)
+ }
+
+ pub fn peek_and_restart(&mut self) -> Result<Option<c::bkey_s_c>, bch_errcode> {
+ unsafe {
+ let k = c::bch2_btree_iter_peek_and_restart_outlined(&mut self.raw);
+
+ errptr_to_result_c(k.k)
+ .map(|_| if !k.k.is_null() { Some(k) } else { None } )
+ }
+ }
+
+ pub fn advance(&mut self) {
+ unsafe {
+ c::bch2_btree_iter_advance(&mut self.raw);
+ }
+
+ }
+}
+
+impl Drop for BtreeIter {
+ fn drop(&mut self) {
+ unsafe { c::bch2_trans_iter_exit(self.raw.trans, &mut self.raw) }
+ }
+}
diff --git a/rust-src/bch_bindgen/src/errcode.rs b/rust-src/bch_bindgen/src/errcode.rs
new file mode 100644
index 00000000..4d75f1d2
--- /dev/null
+++ b/rust-src/bch_bindgen/src/errcode.rs
@@ -0,0 +1,40 @@
+use crate::bcachefs;
+use std::ffi::CStr;
+use std::fmt;
+
+pub use crate::c::bch_errcode;
+
+impl fmt::Display for bch_errcode {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let s = unsafe { CStr::from_ptr(bcachefs::bch2_err_str(*self as i32)) };
+ write!(f, "{:?}", s)
+ }
+}
+
+/* Can we make a function generic over ptr constness? */
+
+pub fn errptr_to_result<T>(p: *mut T) -> Result<*mut T, bch_errcode> {
+ let addr = p as usize;
+ let max_err: isize = -4096;
+ if addr > max_err as usize {
+ let addr = addr as i32;
+ let err: bch_errcode = unsafe { std::mem::transmute(-addr) };
+ Err(err)
+ } else {
+ Ok(p)
+ }
+}
+
+pub fn errptr_to_result_c<T>(p: *const T) -> Result<*const T, bch_errcode> {
+ let addr = p as usize;
+ let max_err: isize = -4096;
+ if addr > max_err as usize {
+ let addr = addr as i32;
+ let err: bch_errcode = unsafe { std::mem::transmute(-addr) };
+ Err(err)
+ } else {
+ Ok(p)
+ }
+}
+
+impl std::error::Error for bch_errcode {}
diff --git a/rust-src/bch_bindgen/src/fs.rs b/rust-src/bch_bindgen/src/fs.rs
new file mode 100644
index 00000000..1176846d
--- /dev/null
+++ b/rust-src/bch_bindgen/src/fs.rs
@@ -0,0 +1,30 @@
+use std::ffi::CString;
+use std::os::unix::ffi::OsStrExt;
+use std::path::PathBuf;
+use crate::c;
+use crate::errcode::{bch_errcode, errptr_to_result};
+
+pub struct Fs {
+ pub raw: *mut c::bch_fs,
+}
+
+impl Fs {
+ pub fn open(devices: &Vec<PathBuf>, opts: c::bch_opts) -> Result<Fs, bch_errcode> {
+ let devices: Vec<_> = devices.iter()
+ .map(|i| CString::new(i.as_os_str().as_bytes()).unwrap()).collect();
+ let dev_c_strs: Vec<_> = devices.iter()
+ .map(|i| { let p: *const i8 = i.as_ptr(); p })
+ .collect();
+ let dev_c_strarray: *const *mut i8 = dev_c_strs[..].as_ptr() as *const *mut i8;
+
+ let ret = unsafe { c::bch2_fs_open(dev_c_strarray, dev_c_strs.len() as u32, opts) };
+
+ errptr_to_result(ret).map(|fs| Fs { raw: fs})
+ }
+}
+
+impl Drop for Fs {
+ fn drop(&mut self) {
+ unsafe { c::bch2_fs_stop(self.raw) }
+ }
+}
diff --git a/rust-src/bch_bindgen/src/lib.rs b/rust-src/bch_bindgen/src/lib.rs
index c54786aa..a5f5a0d5 100644
--- a/rust-src/bch_bindgen/src/lib.rs
+++ b/rust-src/bch_bindgen/src/lib.rs
@@ -1,7 +1,179 @@
pub mod bcachefs;
+pub mod btree;
+pub mod errcode;
pub mod keyutils;
pub mod log;
pub mod rs;
+pub mod fs;
+
pub mod c {
pub use crate::bcachefs::*;
}
+
+use c::bpos as Bpos;
+
+pub const fn spos(inode: u64, offset: u64, snapshot: u32) -> Bpos {
+ Bpos { inode, offset, snapshot }
+}
+
+pub const fn pos(inode: u64, offset: u64) -> Bpos {
+ spos(inode, offset, 0)
+}
+
+pub const POS_MIN: Bpos = spos(0, 0, 0);
+pub const POS_MAX: Bpos = spos(u64::MAX, u64::MAX, 0);
+pub const SPOS_MAX: Bpos = spos(u64::MAX, u64::MAX, u32::MAX);
+
+use std::cmp::Ordering;
+
+impl PartialEq for Bpos {
+ fn eq(&self, other: &Self) -> bool {
+ self.cmp(other) == Ordering::Equal
+ }
+}
+
+impl Eq for Bpos {}
+
+impl PartialOrd for Bpos {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for Bpos {
+ fn cmp(&self, other: &Self) -> Ordering {
+ let l_inode = self.inode;
+ let r_inode = other.inode;
+ let l_offset = self.offset;
+ let r_offset = other.offset;
+ let l_snapshot = self.snapshot;
+ let r_snapshot = other.snapshot;
+
+ l_inode.cmp(&r_inode)
+ .then(l_offset.cmp(&r_offset))
+ .then(l_snapshot.cmp(&r_snapshot))
+ }
+}
+
+use std::ffi::CStr;
+use std::fmt;
+
+impl fmt::Display for c::btree_id {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let s = unsafe { CStr::from_ptr(*c::bch2_btree_ids.get_unchecked(*self as usize)) };
+ let s = s.to_str().unwrap();
+ write!(f, "{}", s)
+ }
+}
+
+use std::str::FromStr;
+use std::ffi::CString;
+
+use std::error::Error;
+
+#[derive(Debug)]
+pub struct InvalidBtreeId;
+
+impl fmt::Display for InvalidBtreeId {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "invalid btree id")
+ }
+}
+
+impl Error for InvalidBtreeId {
+}
+
+impl FromStr for c::btree_id {
+ type Err = InvalidBtreeId;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ let s = CString::new(s).unwrap();
+ let p: *const i8 = s.as_ptr();
+
+ let v = unsafe {c::match_string(c::bch2_btree_ids[..].as_ptr(), (-(1 as isize)) as usize, p)};
+ if v >= 0 {
+ Ok(unsafe { std::mem::transmute(v) })
+ } else {
+ Err(InvalidBtreeId)
+ }
+ }
+}
+
+impl c::printbuf {
+ fn new() -> c::printbuf {
+ let mut buf: c::printbuf = Default::default();
+
+ buf.set_heap_allocated(true);
+ buf
+ }
+}
+
+impl Drop for c::printbuf {
+ fn drop(&mut self) {
+ unsafe { c::bch2_printbuf_exit(self) }
+ }
+}
+
+impl fmt::Display for Bpos {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut buf = c::printbuf::new();
+
+ unsafe { c::bch2_bpos_to_text(&mut buf, *self) };
+
+ let s = unsafe { CStr::from_ptr(buf.buf) };
+ let s = s.to_str().unwrap();
+ write!(f, "{}", s)
+ }
+}
+
+impl FromStr for c::bpos {
+ type Err = InvalidBtreeId;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ if s == "POS_MIN" {
+ return Ok(c::bpos { inode: 0, offset: 0, snapshot: 0 });
+ }
+
+ if s == "POS_MAX" {
+ return Ok(c::bpos { inode: u64::MAX, offset: u64::MAX, snapshot: 0 });
+ }
+
+ if s == "SPOS_MAX" {
+ return Ok(c::bpos { inode: u64::MAX, offset: u64::MAX, snapshot: u32::MAX });
+ }
+
+ let mut fields = s.split(':');
+ let ino_str = fields.next().ok_or(InvalidBtreeId)?;
+ let off_str = fields.next().ok_or(InvalidBtreeId)?;
+ let snp_str = fields.next();
+
+ let ino: u64 = ino_str.parse().map_err(|_| InvalidBtreeId)?;
+ let off: u64 = off_str.parse().map_err(|_| InvalidBtreeId)?;
+ let snp: u32 = snp_str.map(|s| s.parse().ok()).flatten().unwrap_or(0);
+
+ Ok(c::bpos { inode: ino, offset: off, snapshot: snp })
+ }
+}
+
+pub struct BkeySCToText<'a, 'b> {
+ k: &'a c::bkey_s_c,
+ fs: &'b fs::Fs,
+}
+
+impl<'a, 'b> fmt::Display for BkeySCToText<'a, 'b> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut buf = c::printbuf::new();
+
+ unsafe { c::bch2_bkey_val_to_text(&mut buf, self.fs.raw, *self.k) };
+
+ let s = unsafe { CStr::from_ptr(buf.buf) };
+ let s = s.to_str().unwrap();
+ write!(f, "{}", s)
+ }
+}
+
+impl c::bkey_s_c {
+ pub fn to_text<'a, 'b>(&'a self, fs: &'b fs::Fs) -> BkeySCToText<'a, 'b> {
+ BkeySCToText { k: self, fs }
+ }
+}
diff --git a/rust-src/bch_bindgen/src/libbcachefs_wrapper.h b/rust-src/bch_bindgen/src/libbcachefs_wrapper.h
index ec2b5850..6332d957 100644
--- a/rust-src/bch_bindgen/src/libbcachefs_wrapper.h
+++ b/rust-src/bch_bindgen/src/libbcachefs_wrapper.h
@@ -1,6 +1,7 @@
#include "../libbcachefs/super-io.h"
#include "../libbcachefs/checksum.h"
#include "../libbcachefs/bcachefs_format.h"
+#include "../libbcachefs/btree_iter.h"
#include "../libbcachefs/errcode.h"
#include "../libbcachefs/opts.h"
#include "../libbcachefs.h"
diff --git a/rust-src/bch_bindgen/src/rs.rs b/rust-src/bch_bindgen/src/rs.rs
index 17610f3a..24594ae1 100644
--- a/rust-src/bch_bindgen/src/rs.rs
+++ b/rust-src/bch_bindgen/src/rs.rs
@@ -1,15 +1,7 @@
use anyhow::anyhow;
use crate::bcachefs;
use crate::bcachefs::*;
-use std::ffi::CStr;
-use std::fmt;
-
-impl fmt::Display for bch_errcode {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let s = unsafe { CStr::from_ptr(bch2_err_str(*self as i32)) };
- write!(f, "{:?}", s)
- }
-}
+use crate::errcode::bch_errcode;
pub fn read_super_opts(
path: &std::path::Path,