diff options
Diffstat (limited to 'bch_bindgen/src')
-rw-r--r-- | bch_bindgen/src/bcachefs.rs | 112 | ||||
-rw-r--r-- | bch_bindgen/src/bkey.rs | 125 | ||||
-rw-r--r-- | bch_bindgen/src/btree.rs | 197 | ||||
-rw-r--r-- | bch_bindgen/src/errcode.rs | 40 | ||||
-rw-r--r-- | bch_bindgen/src/fs.rs | 27 | ||||
-rw-r--r-- | bch_bindgen/src/keyutils.rs | 6 | ||||
-rw-r--r-- | bch_bindgen/src/keyutils_wrapper.h | 1 | ||||
-rw-r--r-- | bch_bindgen/src/lib.rs | 168 | ||||
-rw-r--r-- | bch_bindgen/src/libbcachefs_wrapper.h | 22 | ||||
-rw-r--r-- | bch_bindgen/src/opts.rs | 35 | ||||
-rw-r--r-- | bch_bindgen/src/rs.rs | 29 |
11 files changed, 762 insertions, 0 deletions
diff --git a/bch_bindgen/src/bcachefs.rs b/bch_bindgen/src/bcachefs.rs new file mode 100644 index 00000000..8e897c08 --- /dev/null +++ b/bch_bindgen/src/bcachefs.rs @@ -0,0 +1,112 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(unused)] + +include!(concat!(env!("OUT_DIR"), "/bcachefs.rs")); + +use bitfield::bitfield; +bitfield! { + pub struct bch_scrypt_flags(u64); + pub N, _: 15, 0; + pub R, _: 31, 16; + pub P, _: 47, 32; +} +bitfield! { + pub struct bch_crypt_flags(u64); + pub TYPE, _: 4, 0; +} +use memoffset::offset_of; +impl bch_sb_field_crypt { + pub fn scrypt_flags(&self) -> Option<bch_scrypt_flags> { + use std::convert::TryInto; + match bch_kdf_types(bch_crypt_flags(self.flags).TYPE().try_into().ok()?) { + bch_kdf_types::BCH_KDF_SCRYPT => Some(bch_scrypt_flags(self.kdf_flags)), + _ => None, + } + } + pub fn key(&self) -> &bch_encrypted_key { + &self.key + } +} +impl PartialEq for bch_sb { + fn eq(&self, other: &Self) -> bool { + self.magic.b == other.magic.b + && self.user_uuid.b == other.user_uuid.b + && self.block_size == other.block_size + && self.version == other.version + && self.uuid.b == other.uuid.b + && self.seq == other.seq + } +} + +impl bch_sb { + pub fn crypt(&self) -> Option<&bch_sb_field_crypt> { + unsafe { + let ptr = bch2_sb_field_get_id( + self as *const _ as *mut _, + bch_sb_field_type::BCH_SB_FIELD_crypt, + ) as *const u8; + if ptr.is_null() { + None + } else { + let offset = offset_of!(bch_sb_field_crypt, field); + Some(&*((ptr.sub(offset)) as *const _)) + } + } + } + pub fn uuid(&self) -> uuid::Uuid { + uuid::Uuid::from_bytes(self.user_uuid.b) + } + + /// Get the nonce used to encrypt the superblock + pub fn nonce(&self) -> nonce { + use byteorder::{LittleEndian, ReadBytesExt}; + let mut internal_uuid = &self.uuid.b[..]; + let dword1 = internal_uuid.read_u32::<LittleEndian>().unwrap(); + let dword2 = internal_uuid.read_u32::<LittleEndian>().unwrap(); + nonce { + d: [0, 0, dword1, dword2], + } + } +} +impl bch_sb_handle { + pub fn sb(&self) -> &bch_sb { + unsafe { &*self.sb } + } + + pub fn bdev(&self) -> &block_device { + unsafe { &*self.bdev } + } +} + +#[repr(C)] +// #[repr(align(8))] +#[derive(Debug, Default, Copy, Clone)] +pub struct bch_extent_ptr { + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 8usize]>, +} + +#[repr(C, packed(8))] +pub struct btree_node { + pub csum: bch_csum, + pub magic: __le64, + pub flags: __le64, + pub min_key: bpos, + pub max_key: bpos, + pub _ptr: bch_extent_ptr, + pub format: bkey_format, + pub __bindgen_anon_1: btree_node__bindgen_ty_1, +} + +#[repr(C, packed(8))] +// #[repr(align(8))] +#[derive(Debug, Default, Copy, Clone)] +pub struct bch_extent_crc32 { + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize]>, + pub csum: __u32, +} + +// #[repr(u8)] +pub enum rhash_lock_head {} +pub enum srcu_struct {} diff --git a/bch_bindgen/src/bkey.rs b/bch_bindgen/src/bkey.rs new file mode 100644 index 00000000..d4830839 --- /dev/null +++ b/bch_bindgen/src/bkey.rs @@ -0,0 +1,125 @@ +#![allow(non_camel_case_types)] + +use crate::c; +use crate::fs::Fs; +use crate::btree::BtreeIter; +use crate::printbuf_to_formatter; +use std::fmt; +use std::marker::PhantomData; +use std::mem::transmute; + +pub struct BkeySC<'a> { + pub k: &'a c::bkey, + pub v: &'a c::bch_val, + pub(crate) iter: PhantomData<&'a mut BtreeIter<'a>> +} + +pub enum BkeyValC<'a> { + deleted, + whiteout, + error, + cookie(&'a c::bch_cookie), + hash_whiteout(&'a c::bch_hash_whiteout), + btree_ptr(&'a c::bch_btree_ptr), + extent(&'a c::bch_extent), + reservation(&'a c::bch_reservation), + inode(&'a c::bch_inode), + inode_generation(&'a c::bch_inode_generation), + dirent(&'a c::bch_dirent), + xattr(&'a c::bch_xattr), + alloc(&'a c::bch_alloc), + quota(&'a c::bch_quota), + stripe(&'a c::bch_stripe), + reflink_p(&'a c::bch_reflink_p), + reflink_v(&'a c::bch_reflink_v), + inline_data(&'a c::bch_inline_data), + btree_ptr_v2(&'a c::bch_btree_ptr_v2), + indirect_inline_data(&'a c::bch_indirect_inline_data), + alloc_v2(&'a c::bch_alloc_v2), + subvolume(&'a c::bch_subvolume), + snapshot(&'a c::bch_snapshot), + inode_v2(&'a c::bch_inode_v2), + alloc_v3(&'a c::bch_alloc_v3), + set, + lru(&'a c::bch_lru), + alloc_v4(&'a c::bch_alloc_v4), + backpointer(&'a c::bch_backpointer), + inode_v3(&'a c::bch_inode_v3), + bucket_gens(&'a c::bch_bucket_gens), + snapshot_tree(&'a c::bch_snapshot_tree), + logged_op_truncate(&'a c::bch_logged_op_truncate), + logged_op_finsert(&'a c::bch_logged_op_finsert), +} + +impl<'a, 'b> BkeySC<'a> { + unsafe fn to_raw(&self) -> c::bkey_s_c { + c::bkey_s_c { k: self.k, v: self.v } + } + + pub fn to_text(&'a self, fs: &'b Fs) -> BkeySCToText<'a, 'b> { + BkeySCToText { k: self, fs } + } + + pub fn v(&'a self) -> BkeyValC { + let ty: c::bch_bkey_type = unsafe { transmute(self.k.type_ as u32) }; + + use c::bch_bkey_type::*; + use BkeyValC::*; + match ty { + KEY_TYPE_deleted => deleted, + KEY_TYPE_whiteout => whiteout, + KEY_TYPE_error => error, + KEY_TYPE_cookie => cookie(unsafe { transmute(self.v) }), + KEY_TYPE_hash_whiteout => hash_whiteout(unsafe { transmute(self.v) }), + KEY_TYPE_btree_ptr => btree_ptr(unsafe { transmute(self.v) }), + KEY_TYPE_extent => extent(unsafe { transmute(self.v) }), + KEY_TYPE_reservation => reservation(unsafe { transmute(self.v) }), + KEY_TYPE_inode => inode(unsafe { transmute(self.v) }), + KEY_TYPE_inode_generation => inode_generation(unsafe { transmute(self.v) }), + KEY_TYPE_dirent => dirent(unsafe { transmute(self.v) }), + KEY_TYPE_xattr => xattr(unsafe { transmute(self.v) }), + KEY_TYPE_alloc => alloc(unsafe { transmute(self.v) }), + KEY_TYPE_quota => quota(unsafe { transmute(self.v) }), + KEY_TYPE_stripe => stripe(unsafe { transmute(self.v) }), + KEY_TYPE_reflink_p => reflink_p(unsafe { transmute(self.v) }), + KEY_TYPE_reflink_v => reflink_v(unsafe { transmute(self.v) }), + KEY_TYPE_inline_data => inline_data(unsafe { transmute(self.v) }), + KEY_TYPE_btree_ptr_v2 => btree_ptr_v2(unsafe { transmute(self.v) }), + KEY_TYPE_indirect_inline_data => indirect_inline_data(unsafe { transmute(self.v) }), + KEY_TYPE_alloc_v2 => alloc_v2(unsafe { transmute(self.v) }), + KEY_TYPE_subvolume => subvolume(unsafe { transmute(self.v) }), + KEY_TYPE_snapshot => snapshot(unsafe { transmute(self.v) }), + KEY_TYPE_inode_v2 => inode_v2(unsafe { transmute(self.v) }), + KEY_TYPE_alloc_v3 => inode_v3(unsafe { transmute(self.v) }), + KEY_TYPE_set => set, + KEY_TYPE_lru => lru(unsafe { transmute(self.v) }), + KEY_TYPE_alloc_v4 => alloc_v4(unsafe { transmute(self.v) }), + KEY_TYPE_backpointer => backpointer(unsafe { transmute(self.v) }), + KEY_TYPE_inode_v3 => inode_v3(unsafe { transmute(self.v) }), + KEY_TYPE_bucket_gens => bucket_gens(unsafe { transmute(self.v) }), + KEY_TYPE_snapshot_tree => snapshot_tree(unsafe { transmute(self.v) }), + KEY_TYPE_logged_op_truncate => logged_op_truncate(unsafe { transmute(self.v) }), + KEY_TYPE_logged_op_finsert => logged_op_finsert(unsafe { transmute(self.v) }), + KEY_TYPE_MAX => unreachable!(), + } + } +} + +impl<'a> From<&'a c::bkey_i> for BkeySC<'a> { + fn from(k: &'a c::bkey_i) -> Self { + BkeySC { k: &k.k, v: &k.v, iter: PhantomData } + } +} + +pub struct BkeySCToText<'a, 'b> { + k: &'a BkeySC<'a>, + fs: &'b Fs, +} + +impl<'a, 'b> fmt::Display for BkeySCToText<'a, 'b> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + unsafe { + printbuf_to_formatter(f, |buf| c::bch2_bkey_val_to_text(buf, self.fs.raw, self.k.to_raw())) + } + } +} diff --git a/bch_bindgen/src/btree.rs b/bch_bindgen/src/btree.rs new file mode 100644 index 00000000..09e86b34 --- /dev/null +++ b/bch_bindgen/src/btree.rs @@ -0,0 +1,197 @@ +use crate::SPOS_MAX; +use crate::c; +use crate::bkey::BkeySC; +use crate::fs::Fs; +use crate::errcode::{bch_errcode, errptr_to_result_c}; +use crate::printbuf_to_formatter; +use std::fmt; +use std::marker::PhantomData; +use std::mem::MaybeUninit; +use bitflags::bitflags; + +pub struct BtreeTrans<'f> { + raw: *mut c::btree_trans, + fs: PhantomData<&'f Fs> +} + +impl<'f> BtreeTrans<'f> { + pub fn new(fs: &'f Fs) -> BtreeTrans { + unsafe { + BtreeTrans { raw: &mut *c::__bch2_trans_get(fs.raw, 0), fs: PhantomData } + } + } +} + +impl<'f> Drop for BtreeTrans<'f> { + fn drop(&mut self) { + unsafe { c::bch2_trans_put(&mut *self.raw) } + } +} + +bitflags! { + pub struct BtreeIterFlags: u16 { + const SLOTS = c::BTREE_ITER_SLOTS as u16; + const INTENT = c::BTREE_ITER_INTENT as u16; + const PREFETCH = c::BTREE_ITER_PREFETCH as u16; + const IS_EXTENTS = c::BTREE_ITER_IS_EXTENTS as u16; + const NOT_EXTENTS = c::BTREE_ITER_NOT_EXTENTS as u16; + const CACHED = c::BTREE_ITER_CACHED as u16; + const KEY_CACHED = c::BTREE_ITER_WITH_KEY_CACHE as u16; + const WITH_UPDATES = c::BTREE_ITER_WITH_UPDATES as u16; + const WITH_JOURNAL = c::BTREE_ITER_WITH_JOURNAL as u16; + const __ALL_SNAPSHOTS = c::__BTREE_ITER_ALL_SNAPSHOTS as u16; + const ALL_SNAPSHOTS = c::BTREE_ITER_ALL_SNAPSHOTS as u16; + const FILTER_SNAPSHOTS = c::BTREE_ITER_FILTER_SNAPSHOTS as u16; + const NOPRESERVE = c::BTREE_ITER_NOPRESERVE as u16; + const CACHED_NOFILL = c::BTREE_ITER_CACHED_NOFILL as u16; + const KEY_CACHE_FILL = c::BTREE_ITER_KEY_CACHE_FILL as u16; + } +} + +pub struct BtreeIter<'t> { + raw: c::btree_iter, + trans: PhantomData<&'t BtreeTrans<'t>>, +} + +impl<'t> BtreeIter<'t> { + pub fn new(trans: &'t BtreeTrans<'t>, btree: c::btree_id, pos: c::bpos, flags: BtreeIterFlags) -> BtreeIter<'t> { + unsafe { + let mut iter: MaybeUninit<c::btree_iter> = MaybeUninit::uninit(); + + c::bch2_trans_iter_init_outlined( + trans.raw, + iter.as_mut_ptr(), + btree, + pos, + flags.bits as u32); + + BtreeIter { raw: iter.assume_init(), trans: PhantomData } + } + } + + pub fn peek_upto<'i>(&'i mut self, end: c::bpos) -> Result<Option<BkeySC>, bch_errcode> { + unsafe { + let k = c::bch2_btree_iter_peek_upto(&mut self.raw, end); + errptr_to_result_c(k.k) + .map(|_| if !k.k.is_null() { Some(BkeySC { k: &*k.k, v: &*k.v, iter: PhantomData }) } else { None } ) + } + } + + pub fn peek(&mut self) -> Result<Option<BkeySC>, bch_errcode> { + self.peek_upto(SPOS_MAX) + } + + pub fn peek_and_restart(&mut self) -> Result<Option<BkeySC>, 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(BkeySC{ k: &*k.k, v: &*k.v, iter: PhantomData }) } else { None } ) + } + } + + pub fn advance(&mut self) { + unsafe { + c::bch2_btree_iter_advance(&mut self.raw); + } + } +} + +impl<'t> Drop for BtreeIter<'t> { + fn drop(&mut self) { + unsafe { c::bch2_trans_iter_exit(self.raw.trans, &mut self.raw) } + } +} + +pub struct BtreeNodeIter<'t> { + raw: c::btree_iter, + trans: PhantomData<&'t BtreeTrans<'t>>, +} + +impl<'t> BtreeNodeIter<'t> { + pub fn new(trans: &'t BtreeTrans<'t>, + btree: c::btree_id, + pos: c::bpos, + locks_want: u32, + depth: u32, + flags: BtreeIterFlags) -> BtreeNodeIter { + unsafe { + let mut iter: MaybeUninit<c::btree_iter> = MaybeUninit::uninit(); + c::bch2_trans_node_iter_init( + trans.raw, + iter.as_mut_ptr(), + btree, + pos, + locks_want, + depth, + flags.bits as u32); + + BtreeNodeIter { raw: iter.assume_init(), trans: PhantomData } + } + } + + pub fn peek<'i>(&'i mut self) -> Result<Option<&'i c::btree>, bch_errcode> { + unsafe { + let b = c::bch2_btree_iter_peek_node(&mut self.raw); + errptr_to_result_c(b).map(|b| if !b.is_null() { Some(&*b) } else { None }) + } + } + + pub fn peek_and_restart<'i>(&'i mut self) -> Result<Option<&'i c::btree>, bch_errcode> { + unsafe { + let b = c::bch2_btree_iter_peek_node_and_restart(&mut self.raw); + errptr_to_result_c(b).map(|b| if !b.is_null() { Some(&*b) } else { None }) + } + } + + pub fn advance<'i>(&'i mut self) { + unsafe { + c::bch2_btree_iter_next_node(&mut self.raw); + } + } + + pub fn next<'i>(&'i mut self) -> Result<Option<&'i c::btree>, bch_errcode> { + unsafe { + let b = c::bch2_btree_iter_next_node(&mut self.raw); + errptr_to_result_c(b).map(|b| if !b.is_null() { Some(&*b) } else { None }) + } + } +} + +impl<'t> Drop for BtreeNodeIter<'t> { + fn drop(&mut self) { + unsafe { c::bch2_trans_iter_exit(self.raw.trans, &mut self.raw) } + } +} + +impl<'b, 'f> c::btree { + pub fn to_text(&'b self, fs: &'f Fs) -> BtreeNodeToText<'b, 'f> { + BtreeNodeToText { b: &self, fs } + } + + pub fn ondisk_to_text(&'b self, fs: &'f Fs) -> BtreeNodeOndiskToText<'b, 'f> { + BtreeNodeOndiskToText { b: &self, fs } + } +} + +pub struct BtreeNodeToText<'b, 'f> { + b: &'b c::btree, + fs: &'f Fs, +} + +impl<'b, 'f> fmt::Display for BtreeNodeToText<'b, 'f> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + printbuf_to_formatter(f, |buf| unsafe { c::bch2_btree_node_to_text(buf, self.fs.raw, self.b) }) + } +} + +pub struct BtreeNodeOndiskToText<'b, 'f> { + b: &'b c::btree, + fs: &'f Fs, +} + +impl<'b, 'f> fmt::Display for BtreeNodeOndiskToText<'b, 'f> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + printbuf_to_formatter(f, |buf| unsafe { c::bch2_btree_node_ondisk_to_text(buf, self.fs.raw, self.b) }) + } +} diff --git a/bch_bindgen/src/errcode.rs b/bch_bindgen/src/errcode.rs new file mode 100644 index 00000000..4d75f1d2 --- /dev/null +++ b/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/bch_bindgen/src/fs.rs b/bch_bindgen/src/fs.rs new file mode 100644 index 00000000..b26c51b6 --- /dev/null +++ b/bch_bindgen/src/fs.rs @@ -0,0 +1,27 @@ +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(devs: &Vec<PathBuf>, opts: c::bch_opts) -> Result<Fs, bch_errcode> { + let devs: Vec<_> = devs.iter() + .map(|i| CString::new(i.as_os_str().as_bytes()).unwrap().into_raw()) + .collect(); + + let ret = unsafe { c::bch2_fs_open(devs[..].as_ptr(), devs.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/bch_bindgen/src/keyutils.rs b/bch_bindgen/src/keyutils.rs new file mode 100644 index 00000000..30fc56f9 --- /dev/null +++ b/bch_bindgen/src/keyutils.rs @@ -0,0 +1,6 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(unused)] + +include!(concat!(env!("OUT_DIR"), "/keyutils.rs")); diff --git a/bch_bindgen/src/keyutils_wrapper.h b/bch_bindgen/src/keyutils_wrapper.h new file mode 100644 index 00000000..857cee2e --- /dev/null +++ b/bch_bindgen/src/keyutils_wrapper.h @@ -0,0 +1 @@ +#include <keyutils.h> diff --git a/bch_bindgen/src/lib.rs b/bch_bindgen/src/lib.rs new file mode 100644 index 00000000..4c549442 --- /dev/null +++ b/bch_bindgen/src/lib.rs @@ -0,0 +1,168 @@ +pub mod bcachefs; +pub mod btree; +pub mod bkey; +pub mod errcode; +pub mod keyutils; +pub mod rs; +pub mod fs; +pub mod opts; +pub use paste::paste; + +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_id_str(*self)) }; + 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 = 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(POS_MIN); + } + + if s == "POS_MAX" { + return Ok(POS_MAX); + } + + if s == "SPOS_MAX" { + return Ok(SPOS_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 fn printbuf_to_formatter<F>(f: &mut fmt::Formatter<'_>, func: F) -> fmt::Result + where F: Fn(*mut c::printbuf) { + let mut buf = c::printbuf::new(); + + func(&mut buf); + + let s = unsafe { CStr::from_ptr(buf.buf) }; + f.write_str(s.to_str().unwrap()) +} diff --git a/bch_bindgen/src/libbcachefs_wrapper.h b/bch_bindgen/src/libbcachefs_wrapper.h new file mode 100644 index 00000000..141b0835 --- /dev/null +++ b/bch_bindgen/src/libbcachefs_wrapper.h @@ -0,0 +1,22 @@ +#include "libbcachefs/super-io.h" +#include "libbcachefs/checksum.h" +#include "libbcachefs/bcachefs_format.h" +#include "libbcachefs/btree_cache.h" +#include "libbcachefs/btree_iter.h" +#include "libbcachefs/debug.h" +#include "libbcachefs/errcode.h" +#include "libbcachefs/error.h" +#include "libbcachefs/opts.h" +#include "libbcachefs.h" +#include "crypto.h" +#include "include/linux/bio.h" +#include "include/linux/blkdev.h" +#include "cmds.h" +#include "raid/raid.h" + + +#define MARK_FIX_753(req_name) const blk_mode_t Fix753_##req_name = req_name; + +MARK_FIX_753(BLK_OPEN_READ); +MARK_FIX_753(BLK_OPEN_WRITE); +MARK_FIX_753(BLK_OPEN_EXCL); diff --git a/bch_bindgen/src/opts.rs b/bch_bindgen/src/opts.rs new file mode 100644 index 00000000..d38d469c --- /dev/null +++ b/bch_bindgen/src/opts.rs @@ -0,0 +1,35 @@ +#[macro_export] +macro_rules! opt_set { + ($opts:ident, $n:ident, $v:expr) => { + bch_bindgen::paste! { + $opts.$n = $v; + $opts.[<set_ $n _defined>](1) + } + }; +} + +#[macro_export] +macro_rules! opt_defined { + ($opts:ident, $n:ident) => { + bch_bindgen::paste! { + $opts.[< $n _defined>]() + } + }; +} + +#[macro_export] +macro_rules! opt_get { + ($opts:ident, $n:ident) => { + if bch_bindgen::opt_defined!($opts, $n) == 0 { + bch_bindgen::paste! { + unsafe { + bch_bindgen::bcachefs::bch2_opts_default.$n + } + } + } else { + bch_bindgen::paste! { + $opts.$n + } + } + }; +} diff --git a/bch_bindgen/src/rs.rs b/bch_bindgen/src/rs.rs new file mode 100644 index 00000000..24594ae1 --- /dev/null +++ b/bch_bindgen/src/rs.rs @@ -0,0 +1,29 @@ +use anyhow::anyhow; +use crate::bcachefs; +use crate::bcachefs::*; +use crate::errcode::bch_errcode; + +pub fn read_super_opts( + path: &std::path::Path, + mut opts: bch_opts, +) -> anyhow::Result<bch_sb_handle> { + use std::os::unix::ffi::OsStrExt; + let path = std::ffi::CString::new(path.as_os_str().as_bytes()).unwrap(); + + let mut sb = std::mem::MaybeUninit::zeroed(); + + let ret = + unsafe { crate::bcachefs::bch2_read_super(path.as_ptr(), &mut opts, sb.as_mut_ptr()) }; + + if ret != 0 { + let err: bch_errcode = unsafe { ::std::mem::transmute(ret) }; + Err(anyhow!(err)) + } else { + Ok(unsafe { sb.assume_init() }) + } +} + +pub fn read_super(path: &std::path::Path) -> anyhow::Result<bch_sb_handle> { + let opts = bcachefs::bch_opts::default(); + read_super_opts(path, opts) +} |