mirror of
https://github.com/koverstreet/bcachefs-tools.git
synced 2025-01-22 00:04:31 +03:00
Format with rustfmt
Note that we're using struct/enum align options, which require nightly. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
5b216318b8
commit
aa985e6a44
@ -29,8 +29,7 @@ fn main() {
|
||||
.to_string(),
|
||||
)
|
||||
.clang_args(
|
||||
urcu
|
||||
.include_paths
|
||||
urcu.include_paths
|
||||
.iter()
|
||||
.map(|p| format!("-I{}", p.display())),
|
||||
)
|
||||
|
@ -1,3 +0,0 @@
|
||||
# Default settings, i.e. idiomatic rust
|
||||
edition = "2021"
|
||||
newline_style = "Unix"
|
@ -1,17 +1,17 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
use crate::btree::BtreeIter;
|
||||
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 k: &'a c::bkey,
|
||||
pub v: &'a c::bch_val,
|
||||
pub(crate) iter: PhantomData<&'a mut BtreeIter<'a>>,
|
||||
}
|
||||
|
||||
pub enum BkeyValC<'a> {
|
||||
@ -53,7 +53,10 @@ pub enum BkeyValC<'a> {
|
||||
|
||||
impl<'a, 'b> BkeySC<'a> {
|
||||
unsafe fn to_raw(&self) -> c::bkey_s_c {
|
||||
c::bkey_s_c { k: self.k, v: self.v }
|
||||
c::bkey_s_c {
|
||||
k: self.k,
|
||||
v: self.v,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_text(&'a self, fs: &'b Fs) -> BkeySCToText<'a, 'b> {
|
||||
@ -67,41 +70,41 @@ impl<'a, 'b> BkeySC<'a> {
|
||||
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(transmute(self.v)),
|
||||
KEY_TYPE_hash_whiteout => hash_whiteout(transmute(self.v)),
|
||||
KEY_TYPE_btree_ptr => btree_ptr(transmute(self.v)),
|
||||
KEY_TYPE_extent => extent(transmute(self.v)),
|
||||
KEY_TYPE_reservation => reservation(transmute(self.v)),
|
||||
KEY_TYPE_inode => inode(transmute(self.v)),
|
||||
KEY_TYPE_inode_generation => inode_generation(transmute(self.v)),
|
||||
KEY_TYPE_dirent => dirent(transmute(self.v)),
|
||||
KEY_TYPE_xattr => xattr(transmute(self.v)),
|
||||
KEY_TYPE_alloc => alloc(transmute(self.v)),
|
||||
KEY_TYPE_quota => quota(transmute(self.v)),
|
||||
KEY_TYPE_stripe => stripe(transmute(self.v)),
|
||||
KEY_TYPE_reflink_p => reflink_p(transmute(self.v)),
|
||||
KEY_TYPE_reflink_v => reflink_v(transmute(self.v)),
|
||||
KEY_TYPE_inline_data => inline_data(transmute(self.v)),
|
||||
KEY_TYPE_btree_ptr_v2 => btree_ptr_v2(transmute(self.v)),
|
||||
KEY_TYPE_indirect_inline_data => indirect_inline_data(transmute(self.v)),
|
||||
KEY_TYPE_alloc_v2 => alloc_v2(transmute(self.v)),
|
||||
KEY_TYPE_subvolume => subvolume(transmute(self.v)),
|
||||
KEY_TYPE_snapshot => snapshot(transmute(self.v)),
|
||||
KEY_TYPE_inode_v2 => inode_v2(transmute(self.v)),
|
||||
KEY_TYPE_alloc_v3 => inode_v3(transmute(self.v)),
|
||||
KEY_TYPE_set => set,
|
||||
KEY_TYPE_lru => lru(transmute(self.v)),
|
||||
KEY_TYPE_alloc_v4 => alloc_v4(transmute(self.v)),
|
||||
KEY_TYPE_backpointer => backpointer(transmute(self.v)),
|
||||
KEY_TYPE_inode_v3 => inode_v3(transmute(self.v)),
|
||||
KEY_TYPE_bucket_gens => bucket_gens(transmute(self.v)),
|
||||
KEY_TYPE_snapshot_tree => snapshot_tree(transmute(self.v)),
|
||||
KEY_TYPE_logged_op_truncate => logged_op_truncate(transmute(self.v)),
|
||||
KEY_TYPE_logged_op_finsert => logged_op_finsert(transmute(self.v)),
|
||||
KEY_TYPE_MAX => unreachable!(),
|
||||
KEY_TYPE_deleted => deleted,
|
||||
KEY_TYPE_whiteout => whiteout,
|
||||
KEY_TYPE_error => error,
|
||||
KEY_TYPE_cookie => cookie(transmute(self.v)),
|
||||
KEY_TYPE_hash_whiteout => hash_whiteout(transmute(self.v)),
|
||||
KEY_TYPE_btree_ptr => btree_ptr(transmute(self.v)),
|
||||
KEY_TYPE_extent => extent(transmute(self.v)),
|
||||
KEY_TYPE_reservation => reservation(transmute(self.v)),
|
||||
KEY_TYPE_inode => inode(transmute(self.v)),
|
||||
KEY_TYPE_inode_generation => inode_generation(transmute(self.v)),
|
||||
KEY_TYPE_dirent => dirent(transmute(self.v)),
|
||||
KEY_TYPE_xattr => xattr(transmute(self.v)),
|
||||
KEY_TYPE_alloc => alloc(transmute(self.v)),
|
||||
KEY_TYPE_quota => quota(transmute(self.v)),
|
||||
KEY_TYPE_stripe => stripe(transmute(self.v)),
|
||||
KEY_TYPE_reflink_p => reflink_p(transmute(self.v)),
|
||||
KEY_TYPE_reflink_v => reflink_v(transmute(self.v)),
|
||||
KEY_TYPE_inline_data => inline_data(transmute(self.v)),
|
||||
KEY_TYPE_btree_ptr_v2 => btree_ptr_v2(transmute(self.v)),
|
||||
KEY_TYPE_indirect_inline_data => indirect_inline_data(transmute(self.v)),
|
||||
KEY_TYPE_alloc_v2 => alloc_v2(transmute(self.v)),
|
||||
KEY_TYPE_subvolume => subvolume(transmute(self.v)),
|
||||
KEY_TYPE_snapshot => snapshot(transmute(self.v)),
|
||||
KEY_TYPE_inode_v2 => inode_v2(transmute(self.v)),
|
||||
KEY_TYPE_alloc_v3 => inode_v3(transmute(self.v)),
|
||||
KEY_TYPE_set => set,
|
||||
KEY_TYPE_lru => lru(transmute(self.v)),
|
||||
KEY_TYPE_alloc_v4 => alloc_v4(transmute(self.v)),
|
||||
KEY_TYPE_backpointer => backpointer(transmute(self.v)),
|
||||
KEY_TYPE_inode_v3 => inode_v3(transmute(self.v)),
|
||||
KEY_TYPE_bucket_gens => bucket_gens(transmute(self.v)),
|
||||
KEY_TYPE_snapshot_tree => snapshot_tree(transmute(self.v)),
|
||||
KEY_TYPE_logged_op_truncate => logged_op_truncate(transmute(self.v)),
|
||||
KEY_TYPE_logged_op_finsert => logged_op_finsert(transmute(self.v)),
|
||||
KEY_TYPE_MAX => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -109,7 +112,11 @@ impl<'a, 'b> BkeySC<'a> {
|
||||
|
||||
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 }
|
||||
BkeySC {
|
||||
k: &k.k,
|
||||
v: &k.v,
|
||||
iter: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,7 +128,9 @@ pub struct BkeySCToText<'a, 'b> {
|
||||
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()))
|
||||
printbuf_to_formatter(f, |buf| {
|
||||
c::bch2_bkey_val_to_text(buf, self.fs.raw, self.k.to_raw())
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,26 @@
|
||||
use crate::SPOS_MAX;
|
||||
use crate::c;
|
||||
use crate::bkey::BkeySC;
|
||||
use crate::fs::Fs;
|
||||
use crate::c;
|
||||
use crate::errcode::{bch_errcode, errptr_to_result_c};
|
||||
use crate::fs::Fs;
|
||||
use crate::printbuf_to_formatter;
|
||||
use crate::SPOS_MAX;
|
||||
use bitflags::bitflags;
|
||||
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>
|
||||
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 }
|
||||
BtreeTrans {
|
||||
raw: &mut *c::__bch2_trans_get(fs.raw, 0),
|
||||
fs: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -25,7 +28,7 @@ impl<'f> BtreeTrans<'f> {
|
||||
impl<'f> Drop for BtreeTrans<'f> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { c::bch2_trans_put(&mut *self.raw) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
@ -49,12 +52,17 @@ bitflags! {
|
||||
}
|
||||
|
||||
pub struct BtreeIter<'t> {
|
||||
raw: c::btree_iter,
|
||||
trans: PhantomData<&'t BtreeTrans<'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> {
|
||||
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();
|
||||
|
||||
@ -63,17 +71,30 @@ impl<'t> BtreeIter<'t> {
|
||||
iter.as_mut_ptr(),
|
||||
btree,
|
||||
pos,
|
||||
flags.bits as u32);
|
||||
flags.bits as u32,
|
||||
);
|
||||
|
||||
BtreeIter { raw: iter.assume_init(), trans: PhantomData }
|
||||
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 } )
|
||||
errptr_to_result_c(k.k).map(|_| {
|
||||
if !k.k.is_null() {
|
||||
Some(BkeySC {
|
||||
k: &*k.k,
|
||||
v: &*k.v,
|
||||
iter: PhantomData,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,8 +106,17 @@ impl<'t> BtreeIter<'t> {
|
||||
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 } )
|
||||
errptr_to_result_c(k.k).map(|_| {
|
||||
if !k.k.is_null() {
|
||||
Some(BkeySC {
|
||||
k: &*k.k,
|
||||
v: &*k.v,
|
||||
iter: PhantomData,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,21 +130,23 @@ impl<'t> BtreeIter<'t> {
|
||||
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>>,
|
||||
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,
|
||||
pub fn new(
|
||||
trans: &'t BtreeTrans<'t>,
|
||||
btree: c::btree_id,
|
||||
pos: c::bpos,
|
||||
locks_want: u32,
|
||||
depth: u32,
|
||||
flags: BtreeIterFlags) -> BtreeNodeIter {
|
||||
depth: u32,
|
||||
flags: BtreeIterFlags,
|
||||
) -> BtreeNodeIter {
|
||||
unsafe {
|
||||
let mut iter: MaybeUninit<c::btree_iter> = MaybeUninit::uninit();
|
||||
c::bch2_trans_node_iter_init(
|
||||
@ -124,9 +156,13 @@ impl<'t> BtreeNodeIter<'t> {
|
||||
pos,
|
||||
locks_want,
|
||||
depth,
|
||||
flags.bits as u32);
|
||||
flags.bits as u32,
|
||||
);
|
||||
|
||||
BtreeNodeIter { raw: iter.assume_init(), trans: PhantomData }
|
||||
BtreeNodeIter {
|
||||
raw: iter.assume_init(),
|
||||
trans: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,7 +197,7 @@ impl<'t> BtreeNodeIter<'t> {
|
||||
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 {
|
||||
@ -175,23 +211,27 @@ impl<'b, 'f> c::btree {
|
||||
}
|
||||
|
||||
pub struct BtreeNodeToText<'b, 'f> {
|
||||
b: &'b c::btree,
|
||||
fs: &'f Fs,
|
||||
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) })
|
||||
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,
|
||||
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) })
|
||||
printbuf_to_formatter(f, |buf| unsafe {
|
||||
c::bch2_btree_node_ondisk_to_text(buf, self.fs.raw, self.b)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::c;
|
||||
use crate::errcode::{bch_errcode, errptr_to_result};
|
||||
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,
|
||||
@ -10,18 +10,19 @@ pub struct Fs {
|
||||
|
||||
impl Fs {
|
||||
pub fn open(devs: &Vec<PathBuf>, opts: c::bch_opts) -> Result<Fs, bch_errcode> {
|
||||
let devs: Vec<_> = devs.iter()
|
||||
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})
|
||||
errptr_to_result(ret).map(|fs| Fs { raw: fs })
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Fs {
|
||||
fn drop(&mut self) {
|
||||
unsafe { c::bch2_fs_stop(self.raw) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
pub mod bcachefs;
|
||||
pub mod btree;
|
||||
pub mod bkey;
|
||||
pub mod btree;
|
||||
pub mod errcode;
|
||||
pub mod keyutils;
|
||||
pub mod sb_io;
|
||||
pub mod fs;
|
||||
pub mod keyutils;
|
||||
pub mod opts;
|
||||
pub mod sb_io;
|
||||
pub use paste::paste;
|
||||
|
||||
pub mod c {
|
||||
@ -15,15 +15,19 @@ pub mod c {
|
||||
use c::bpos as Bpos;
|
||||
|
||||
pub const fn spos(inode: u64, offset: u64, snapshot: u32) -> Bpos {
|
||||
Bpos { inode, offset, snapshot }
|
||||
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 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;
|
||||
@ -44,14 +48,15 @@ impl PartialOrd for Bpos {
|
||||
|
||||
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;
|
||||
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)
|
||||
l_inode
|
||||
.cmp(&r_inode)
|
||||
.then(l_offset.cmp(&r_offset))
|
||||
.then(l_snapshot.cmp(&r_snapshot))
|
||||
}
|
||||
@ -68,9 +73,9 @@ impl fmt::Display for c::btree_id {
|
||||
}
|
||||
}
|
||||
|
||||
use std::str::FromStr;
|
||||
use std::ffi::CString;
|
||||
use std::{path::Path,os::unix::ffi::OsStrExt};
|
||||
use std::str::FromStr;
|
||||
use std::{os::unix::ffi::OsStrExt, path::Path};
|
||||
|
||||
pub fn path_to_cstr<P: AsRef<Path>>(p: P) -> CString {
|
||||
CString::new(p.as_ref().as_os_str().as_bytes()).unwrap()
|
||||
@ -95,8 +100,7 @@ impl fmt::Display for BchToolsErr {
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for BchToolsErr {
|
||||
}
|
||||
impl Error for BchToolsErr {}
|
||||
|
||||
impl FromStr for c::btree_id {
|
||||
type Err = BchToolsErr;
|
||||
@ -105,7 +109,13 @@ impl FromStr for c::btree_id {
|
||||
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)};
|
||||
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 {
|
||||
@ -121,7 +131,9 @@ impl FromStr for c::bch_bkey_type {
|
||||
let s = CString::new(s).unwrap();
|
||||
let p = s.as_ptr();
|
||||
|
||||
let v = unsafe {c::match_string(c::bch2_bkey_types[..].as_ptr(), (-(1 as isize)) as usize, p)};
|
||||
let v = unsafe {
|
||||
c::match_string(c::bch2_bkey_types[..].as_ptr(), (-(1 as isize)) as usize, p)
|
||||
};
|
||||
if v >= 0 {
|
||||
Ok(unsafe { std::mem::transmute(v) })
|
||||
} else {
|
||||
@ -142,7 +154,7 @@ impl c::printbuf {
|
||||
impl Drop for c::printbuf {
|
||||
fn drop(&mut self) {
|
||||
unsafe { c::bch2_printbuf_exit(self) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Bpos {
|
||||
@ -150,7 +162,7 @@ impl fmt::Display for Bpos {
|
||||
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)
|
||||
@ -178,16 +190,22 @@ impl FromStr for c::bpos {
|
||||
let off_str = fields.next().ok_or(BchToolsErr::InvalidBpos)?;
|
||||
let snp_str = fields.next();
|
||||
|
||||
let ino: u64 = ino_str.parse().map_err(|_| BchToolsErr::InvalidBpos)?;
|
||||
let off: u64 = off_str.parse().map_err(|_| BchToolsErr::InvalidBpos)?;
|
||||
let snp: u32 = snp_str.map(|s| s.parse().ok()).flatten().unwrap_or(0);
|
||||
let ino: u64 = ino_str.parse().map_err(|_| BchToolsErr::InvalidBpos)?;
|
||||
let off: u64 = off_str.parse().map_err(|_| BchToolsErr::InvalidBpos)?;
|
||||
let snp: u32 = snp_str.map(|s| s.parse().ok()).flatten().unwrap_or(0);
|
||||
|
||||
Ok(c::bpos { inode: ino, offset: off, snapshot: snp })
|
||||
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) {
|
||||
where
|
||||
F: Fn(*mut c::printbuf),
|
||||
{
|
||||
let mut buf = c::printbuf::new();
|
||||
|
||||
func(&mut buf);
|
||||
|
@ -1,8 +1,8 @@
|
||||
use anyhow::anyhow;
|
||||
use crate::path_to_cstr;
|
||||
use crate::bcachefs;
|
||||
use crate::bcachefs::*;
|
||||
use crate::errcode::bch_errcode;
|
||||
use crate::path_to_cstr;
|
||||
use anyhow::anyhow;
|
||||
|
||||
pub fn read_super_opts(
|
||||
path: &std::path::Path,
|
||||
@ -11,7 +11,8 @@ pub fn read_super_opts(
|
||||
let path = path_to_cstr(path);
|
||||
let mut sb = std::mem::MaybeUninit::zeroed();
|
||||
|
||||
let ret = unsafe { crate::bcachefs::bch2_read_super(path.as_ptr(), &mut opts, sb.as_mut_ptr()) };
|
||||
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) };
|
||||
@ -33,7 +34,9 @@ pub fn read_super_silent(
|
||||
let path = path_to_cstr(path);
|
||||
let mut sb = std::mem::MaybeUninit::zeroed();
|
||||
|
||||
let ret = unsafe { crate::bcachefs::bch2_read_super_silent(path.as_ptr(), &mut opts, sb.as_mut_ptr()) };
|
||||
let ret = unsafe {
|
||||
crate::bcachefs::bch2_read_super_silent(path.as_ptr(), &mut opts, sb.as_mut_ptr())
|
||||
};
|
||||
|
||||
if ret != 0 {
|
||||
let err: bch_errcode = unsafe { ::std::mem::transmute(ret) };
|
||||
|
@ -1,3 +1,5 @@
|
||||
# Default settings, i.e. idiomatic rust
|
||||
edition = "2021"
|
||||
newline_style = "Unix"
|
||||
newline_style = "Unix"
|
||||
enum_discrim_align_threshold = 20
|
||||
struct_field_align_threshold = 20
|
||||
|
@ -1,11 +1,11 @@
|
||||
mod wrappers;
|
||||
mod commands;
|
||||
mod key;
|
||||
mod wrappers;
|
||||
|
||||
use std::ffi::{c_char, CString};
|
||||
|
||||
use commands::logger::SimpleLogger;
|
||||
use bch_bindgen::c;
|
||||
use commands::logger::SimpleLogger;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ErrnoError(pub errno::Errno);
|
||||
@ -25,10 +25,7 @@ fn handle_c_command(mut argv: Vec<String>, symlink_cmd: Option<&str>) -> i32 {
|
||||
|
||||
let argc: i32 = argv.len().try_into().unwrap();
|
||||
|
||||
let argv: Vec<_> = argv
|
||||
.into_iter()
|
||||
.map(|s| CString::new(s).unwrap())
|
||||
.collect();
|
||||
let argv: Vec<_> = argv.into_iter().map(|s| CString::new(s).unwrap()).collect();
|
||||
let mut argv = argv
|
||||
.into_iter()
|
||||
.map(|s| Box::into_raw(s.into_boxed_c_str()) as *mut c_char)
|
||||
@ -41,7 +38,7 @@ fn handle_c_command(mut argv: Vec<String>, symlink_cmd: Option<&str>) -> i32 {
|
||||
"--help" => {
|
||||
c::bcachefs_usage();
|
||||
0
|
||||
},
|
||||
}
|
||||
"data" => c::data_cmds(argc, argv),
|
||||
"device" => c::device_cmds(argc, argv),
|
||||
"dump" => c::cmd_dump(argc, argv),
|
||||
|
@ -1,20 +1,23 @@
|
||||
use log::{error};
|
||||
use bch_bindgen::bcachefs;
|
||||
use bch_bindgen::opt_set;
|
||||
use bch_bindgen::fs::Fs;
|
||||
use bch_bindgen::bkey::BkeySC;
|
||||
use bch_bindgen::btree::BtreeTrans;
|
||||
use bch_bindgen::btree::BtreeIter;
|
||||
use bch_bindgen::btree::BtreeNodeIter;
|
||||
use bch_bindgen::btree::BtreeIterFlags;
|
||||
use clap::{Parser};
|
||||
use bch_bindgen::btree::BtreeNodeIter;
|
||||
use bch_bindgen::btree::BtreeTrans;
|
||||
use bch_bindgen::fs::Fs;
|
||||
use bch_bindgen::opt_set;
|
||||
use clap::Parser;
|
||||
use log::error;
|
||||
use std::io::{stdout, IsTerminal};
|
||||
|
||||
fn list_keys(fs: &Fs, opt: Cli) -> anyhow::Result<()> {
|
||||
let trans = BtreeTrans::new(fs);
|
||||
let mut iter = BtreeIter::new(&trans, opt.btree, opt.start,
|
||||
BtreeIterFlags::ALL_SNAPSHOTS|
|
||||
BtreeIterFlags::PREFETCH);
|
||||
let mut iter = BtreeIter::new(
|
||||
&trans,
|
||||
opt.btree,
|
||||
opt.start,
|
||||
BtreeIterFlags::ALL_SNAPSHOTS | BtreeIterFlags::PREFETCH,
|
||||
);
|
||||
|
||||
while let Some(k) = iter.peek_and_restart()? {
|
||||
if k.k.p > opt.end {
|
||||
@ -37,9 +40,14 @@ fn list_keys(fs: &Fs, opt: Cli) -> anyhow::Result<()> {
|
||||
|
||||
fn list_btree_formats(fs: &Fs, opt: Cli) -> anyhow::Result<()> {
|
||||
let trans = BtreeTrans::new(fs);
|
||||
let mut iter = BtreeNodeIter::new(&trans, opt.btree, opt.start,
|
||||
0, opt.level,
|
||||
BtreeIterFlags::PREFETCH);
|
||||
let mut iter = BtreeNodeIter::new(
|
||||
&trans,
|
||||
opt.btree,
|
||||
opt.start,
|
||||
0,
|
||||
opt.level,
|
||||
BtreeIterFlags::PREFETCH,
|
||||
);
|
||||
|
||||
while let Some(b) = iter.peek_and_restart()? {
|
||||
if b.key.k.p > opt.end {
|
||||
@ -55,9 +63,14 @@ fn list_btree_formats(fs: &Fs, opt: Cli) -> anyhow::Result<()> {
|
||||
|
||||
fn list_btree_nodes(fs: &Fs, opt: Cli) -> anyhow::Result<()> {
|
||||
let trans = BtreeTrans::new(fs);
|
||||
let mut iter = BtreeNodeIter::new(&trans, opt.btree, opt.start,
|
||||
0, opt.level,
|
||||
BtreeIterFlags::PREFETCH);
|
||||
let mut iter = BtreeNodeIter::new(
|
||||
&trans,
|
||||
opt.btree,
|
||||
opt.start,
|
||||
0,
|
||||
opt.level,
|
||||
BtreeIterFlags::PREFETCH,
|
||||
);
|
||||
|
||||
while let Some(b) = iter.peek_and_restart()? {
|
||||
if b.key.k.p > opt.end {
|
||||
@ -73,9 +86,14 @@ fn list_btree_nodes(fs: &Fs, opt: Cli) -> anyhow::Result<()> {
|
||||
|
||||
fn list_nodes_ondisk(fs: &Fs, opt: Cli) -> anyhow::Result<()> {
|
||||
let trans = BtreeTrans::new(fs);
|
||||
let mut iter = BtreeNodeIter::new(&trans, opt.btree, opt.start,
|
||||
0, opt.level,
|
||||
BtreeIterFlags::PREFETCH);
|
||||
let mut iter = BtreeNodeIter::new(
|
||||
&trans,
|
||||
opt.btree,
|
||||
opt.start,
|
||||
0,
|
||||
opt.level,
|
||||
BtreeIterFlags::PREFETCH,
|
||||
);
|
||||
|
||||
while let Some(b) = iter.peek_and_restart()? {
|
||||
if b.key.k.p > opt.end {
|
||||
@ -102,69 +120,77 @@ enum Mode {
|
||||
pub struct Cli {
|
||||
/// Btree to list from
|
||||
#[arg(short, long, default_value_t=bcachefs::btree_id::BTREE_ID_extents)]
|
||||
btree: bcachefs::btree_id,
|
||||
btree: bcachefs::btree_id,
|
||||
|
||||
/// Bkey type to list
|
||||
#[arg(short='k', long)]
|
||||
bkey_type: Option<bcachefs::bch_bkey_type>,
|
||||
#[arg(short = 'k', long)]
|
||||
bkey_type: Option<bcachefs::bch_bkey_type>,
|
||||
|
||||
/// Btree depth to descend to (0 == leaves)
|
||||
#[arg(short, long, default_value_t=0)]
|
||||
level: u32,
|
||||
#[arg(short, long, default_value_t = 0)]
|
||||
level: u32,
|
||||
|
||||
/// Start position to list from
|
||||
#[arg(short, long, default_value="POS_MIN")]
|
||||
start: bcachefs::bpos,
|
||||
#[arg(short, long, default_value = "POS_MIN")]
|
||||
start: bcachefs::bpos,
|
||||
|
||||
/// End position
|
||||
#[arg(short, long, default_value="SPOS_MAX")]
|
||||
end: bcachefs::bpos,
|
||||
#[arg(short, long, default_value = "SPOS_MAX")]
|
||||
end: bcachefs::bpos,
|
||||
|
||||
#[arg(short, long, default_value="keys")]
|
||||
mode: Mode,
|
||||
#[arg(short, long, default_value = "keys")]
|
||||
mode: Mode,
|
||||
|
||||
/// Check (fsck) the filesystem first
|
||||
#[arg(short, long)]
|
||||
fsck: bool,
|
||||
fsck: bool,
|
||||
|
||||
/// Force color on/off. Default: autodetect tty
|
||||
#[arg(short, long, action = clap::ArgAction::Set, default_value_t=stdout().is_terminal())]
|
||||
colorize: bool,
|
||||
colorize: bool,
|
||||
|
||||
/// Verbose mode
|
||||
#[arg(short, long)]
|
||||
verbose: bool,
|
||||
verbose: bool,
|
||||
|
||||
#[arg(required(true))]
|
||||
devices: Vec<std::path::PathBuf>,
|
||||
devices: Vec<std::path::PathBuf>,
|
||||
}
|
||||
|
||||
fn cmd_list_inner(opt: Cli) -> anyhow::Result<()> {
|
||||
let mut fs_opts: bcachefs::bch_opts = Default::default();
|
||||
|
||||
opt_set!(fs_opts, nochanges, 1);
|
||||
opt_set!(fs_opts, read_only, 1);
|
||||
opt_set!(fs_opts, norecovery, 1);
|
||||
opt_set!(fs_opts, degraded, 1);
|
||||
opt_set!(fs_opts, very_degraded, 1);
|
||||
opt_set!(fs_opts, errors, bcachefs::bch_error_actions::BCH_ON_ERROR_continue as u8);
|
||||
opt_set!(fs_opts, nochanges, 1);
|
||||
opt_set!(fs_opts, read_only, 1);
|
||||
opt_set!(fs_opts, norecovery, 1);
|
||||
opt_set!(fs_opts, degraded, 1);
|
||||
opt_set!(fs_opts, very_degraded, 1);
|
||||
opt_set!(
|
||||
fs_opts,
|
||||
errors,
|
||||
bcachefs::bch_error_actions::BCH_ON_ERROR_continue as u8
|
||||
);
|
||||
|
||||
if opt.fsck {
|
||||
opt_set!(fs_opts, fix_errors, bcachefs::fsck_err_opts::FSCK_FIX_yes as u8);
|
||||
opt_set!(fs_opts, norecovery, 0);
|
||||
opt_set!(
|
||||
fs_opts,
|
||||
fix_errors,
|
||||
bcachefs::fsck_err_opts::FSCK_FIX_yes as u8
|
||||
);
|
||||
opt_set!(fs_opts, norecovery, 0);
|
||||
}
|
||||
|
||||
if opt.verbose {
|
||||
opt_set!(fs_opts, verbose, 1);
|
||||
opt_set!(fs_opts, verbose, 1);
|
||||
}
|
||||
|
||||
let fs = Fs::open(&opt.devices, fs_opts)?;
|
||||
|
||||
match opt.mode {
|
||||
Mode::Keys => list_keys(&fs, opt),
|
||||
Mode::Formats => list_btree_formats(&fs, opt),
|
||||
Mode::Nodes => list_btree_nodes(&fs, opt),
|
||||
Mode::NodesOndisk => list_nodes_ondisk(&fs, opt),
|
||||
Mode::Keys => list_keys(&fs, opt),
|
||||
Mode::Formats => list_btree_formats(&fs, opt),
|
||||
Mode::Nodes => list_btree_nodes(&fs, opt),
|
||||
Mode::NodesOndisk => list_nodes_ondisk(&fs, opt),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
use clap::Subcommand;
|
||||
|
||||
pub mod completions;
|
||||
pub mod list;
|
||||
pub mod logger;
|
||||
pub mod mount;
|
||||
pub mod list;
|
||||
pub mod completions;
|
||||
pub mod subvolume;
|
||||
|
||||
pub use mount::mount;
|
||||
pub use list::list;
|
||||
pub use completions::completions;
|
||||
pub use list::list;
|
||||
pub use mount::mount;
|
||||
pub use subvolume::subvolume;
|
||||
|
||||
#[derive(clap::Parser, Debug)]
|
||||
|
@ -1,14 +1,14 @@
|
||||
use bch_bindgen::{path_to_cstr, bcachefs, bcachefs::bch_sb_handle, opt_set};
|
||||
use log::{info, debug, error, LevelFilter};
|
||||
use std::collections::HashMap;
|
||||
use clap::Parser;
|
||||
use uuid::Uuid;
|
||||
use std::io::{stdout, IsTerminal};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{fs, str, env};
|
||||
use crate::key;
|
||||
use crate::key::UnlockPolicy;
|
||||
use std::ffi::{CString, c_char, c_void};
|
||||
use bch_bindgen::{bcachefs, bcachefs::bch_sb_handle, opt_set, path_to_cstr};
|
||||
use clap::Parser;
|
||||
use log::{debug, error, info, LevelFilter};
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::{c_char, c_void, CString};
|
||||
use std::io::{stdout, IsTerminal};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{env, fs, str};
|
||||
use uuid::Uuid;
|
||||
|
||||
fn mount_inner(
|
||||
src: String,
|
||||
@ -17,7 +17,6 @@ fn mount_inner(
|
||||
mountflags: libc::c_ulong,
|
||||
data: Option<String>,
|
||||
) -> anyhow::Result<()> {
|
||||
|
||||
// bind the CStrings to keep them alive
|
||||
let src = CString::new(src)?;
|
||||
let target = path_to_cstr(target);
|
||||
@ -52,22 +51,22 @@ fn parse_mount_options(options: impl AsRef<str>) -> (Option<String>, libc::c_ulo
|
||||
.as_ref()
|
||||
.split(',')
|
||||
.map(|o| match o {
|
||||
"dirsync" => Left(libc::MS_DIRSYNC),
|
||||
"lazytime" => Left(1 << 25), // MS_LAZYTIME
|
||||
"mand" => Left(libc::MS_MANDLOCK),
|
||||
"noatime" => Left(libc::MS_NOATIME),
|
||||
"nodev" => Left(libc::MS_NODEV),
|
||||
"nodiratime" => Left(libc::MS_NODIRATIME),
|
||||
"noexec" => Left(libc::MS_NOEXEC),
|
||||
"nosuid" => Left(libc::MS_NOSUID),
|
||||
"relatime" => Left(libc::MS_RELATIME),
|
||||
"remount" => Left(libc::MS_REMOUNT),
|
||||
"ro" => Left(libc::MS_RDONLY),
|
||||
"rw" => Left(0),
|
||||
"strictatime" => Left(libc::MS_STRICTATIME),
|
||||
"sync" => Left(libc::MS_SYNCHRONOUS),
|
||||
"" => Left(0),
|
||||
o => Right(o),
|
||||
"dirsync" => Left(libc::MS_DIRSYNC),
|
||||
"lazytime" => Left(1 << 25), // MS_LAZYTIME
|
||||
"mand" => Left(libc::MS_MANDLOCK),
|
||||
"noatime" => Left(libc::MS_NOATIME),
|
||||
"nodev" => Left(libc::MS_NODEV),
|
||||
"nodiratime" => Left(libc::MS_NODIRATIME),
|
||||
"noexec" => Left(libc::MS_NOEXEC),
|
||||
"nosuid" => Left(libc::MS_NOSUID),
|
||||
"relatime" => Left(libc::MS_RELATIME),
|
||||
"remount" => Left(libc::MS_REMOUNT),
|
||||
"ro" => Left(libc::MS_RDONLY),
|
||||
"rw" => Left(0),
|
||||
"strictatime" => Left(libc::MS_STRICTATIME),
|
||||
"sync" => Left(libc::MS_SYNCHRONOUS),
|
||||
"" => Left(0),
|
||||
o => Right(o),
|
||||
})
|
||||
.fold((Vec::new(), 0), |(mut opts, flags), next| match next {
|
||||
Left(f) => (opts, flags | f),
|
||||
@ -235,7 +234,7 @@ pub struct Cli {
|
||||
/// by the specified passphrase file; it is decrypted. (i.e. Regardless
|
||||
/// if "fail" is specified for key_location/unlock_policy.)
|
||||
#[arg(short = 'f', long)]
|
||||
passphrase_file: Option<PathBuf>,
|
||||
passphrase_file: Option<PathBuf>,
|
||||
|
||||
/// Password policy to use in case of encrypted filesystem.
|
||||
///
|
||||
@ -243,28 +242,33 @@ pub struct Cli {
|
||||
/// "fail" - don't ask for password, fail if filesystem is encrypted;
|
||||
/// "wait" - wait for password to become available before mounting;
|
||||
/// "ask" - prompt the user for password;
|
||||
#[arg(short = 'k', long = "key_location", default_value = "ask", verbatim_doc_comment)]
|
||||
unlock_policy: UnlockPolicy,
|
||||
#[arg(
|
||||
short = 'k',
|
||||
long = "key_location",
|
||||
default_value = "ask",
|
||||
verbatim_doc_comment
|
||||
)]
|
||||
unlock_policy: UnlockPolicy,
|
||||
|
||||
/// Device, or UUID=\<UUID\>
|
||||
dev: String,
|
||||
dev: String,
|
||||
|
||||
/// Where the filesystem should be mounted. If not set, then the filesystem
|
||||
/// won't actually be mounted. But all steps preceeding mounting the
|
||||
/// filesystem (e.g. asking for passphrase) will still be performed.
|
||||
mountpoint: Option<PathBuf>,
|
||||
mountpoint: Option<PathBuf>,
|
||||
|
||||
/// Mount options
|
||||
#[arg(short, default_value = "")]
|
||||
options: String,
|
||||
options: String,
|
||||
|
||||
/// Force color on/off. Autodetect tty is used to define default:
|
||||
#[arg(short, long, action = clap::ArgAction::Set, default_value_t=stdout().is_terminal())]
|
||||
colorize: bool,
|
||||
colorize: bool,
|
||||
|
||||
/// Verbose mode
|
||||
#[arg(short, long, action = clap::ArgAction::Count)]
|
||||
verbose: u8,
|
||||
verbose: u8,
|
||||
}
|
||||
|
||||
fn devs_str_sbs_from_uuid(
|
||||
@ -358,7 +362,10 @@ fn cmd_mount_inner(opt: Cli) -> anyhow::Result<()> {
|
||||
{
|
||||
// First by password_file, if available
|
||||
let fallback_to_unlock_policy = if let Some(passphrase_file) = &opt.passphrase_file {
|
||||
match key::read_from_passphrase_file(&block_devices_to_mount[0], passphrase_file.as_path()) {
|
||||
match key::read_from_passphrase_file(
|
||||
&block_devices_to_mount[0],
|
||||
passphrase_file.as_path(),
|
||||
) {
|
||||
Ok(()) => {
|
||||
// Decryption succeeded
|
||||
false
|
||||
@ -391,8 +398,7 @@ fn cmd_mount_inner(opt: Cli) -> anyhow::Result<()> {
|
||||
} else {
|
||||
info!(
|
||||
"would mount with params: device: {}, options: {}",
|
||||
devices,
|
||||
&opt.options
|
||||
devices, &opt.options
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -17,13 +17,13 @@ enum Subcommands {
|
||||
#[command(visible_aliases = ["new"])]
|
||||
Create {
|
||||
/// Paths
|
||||
targets: Vec<PathBuf>
|
||||
targets: Vec<PathBuf>,
|
||||
},
|
||||
|
||||
#[command(visible_aliases = ["del"])]
|
||||
Delete {
|
||||
/// Path
|
||||
target: PathBuf
|
||||
target: PathBuf,
|
||||
},
|
||||
|
||||
#[command(allow_missing_positional = true, visible_aliases = ["snap"])]
|
||||
@ -31,9 +31,9 @@ enum Subcommands {
|
||||
/// Make snapshot read only
|
||||
#[arg(long, short)]
|
||||
read_only: bool,
|
||||
source: Option<PathBuf>,
|
||||
dest: PathBuf
|
||||
}
|
||||
source: Option<PathBuf>,
|
||||
dest: PathBuf,
|
||||
},
|
||||
}
|
||||
|
||||
pub fn subvolume(argv: Vec<String>) -> i32 {
|
||||
@ -44,24 +44,42 @@ pub fn subvolume(argv: Vec<String>) -> i32 {
|
||||
for target in targets {
|
||||
if let Some(dirname) = target.parent() {
|
||||
let fs = unsafe { BcachefsHandle::open(dirname) };
|
||||
fs.create_subvolume(target).expect("Failed to create the subvolume");
|
||||
fs.create_subvolume(target)
|
||||
.expect("Failed to create the subvolume");
|
||||
}
|
||||
}
|
||||
}
|
||||
,
|
||||
Subcommands::Delete { target } => {
|
||||
if let Some(dirname) = target.parent() {
|
||||
let fs = unsafe { BcachefsHandle::open(dirname) };
|
||||
fs.delete_subvolume(target).expect("Failed to delete the subvolume");
|
||||
fs.delete_subvolume(target)
|
||||
.expect("Failed to delete the subvolume");
|
||||
}
|
||||
},
|
||||
Subcommands::Snapshot { read_only, source, dest } => {
|
||||
}
|
||||
Subcommands::Snapshot {
|
||||
read_only,
|
||||
source,
|
||||
dest,
|
||||
} => {
|
||||
if let Some(dirname) = dest.parent() {
|
||||
let dot = PathBuf::from(".");
|
||||
let dir = if dirname.as_os_str().is_empty() { &dot } else { dirname };
|
||||
let dir = if dirname.as_os_str().is_empty() {
|
||||
&dot
|
||||
} else {
|
||||
dirname
|
||||
};
|
||||
let fs = unsafe { BcachefsHandle::open(dir) };
|
||||
|
||||
fs.snapshot_subvolume(if read_only { BCH_SUBVOL_SNAPSHOT_RO } else { 0x0 }, source, dest).expect("Failed to snapshot the subvolume");
|
||||
fs.snapshot_subvolume(
|
||||
if read_only {
|
||||
BCH_SUBVOL_SNAPSHOT_RO
|
||||
} else {
|
||||
0x0
|
||||
},
|
||||
source,
|
||||
dest,
|
||||
)
|
||||
.expect("Failed to snapshot the subvolume");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
43
src/key.rs
43
src/key.rs
@ -1,10 +1,13 @@
|
||||
use std::{fmt, fs, io::{stdin, IsTerminal}};
|
||||
use std::{
|
||||
fmt, fs,
|
||||
io::{stdin, IsTerminal},
|
||||
};
|
||||
|
||||
use log::info;
|
||||
use bch_bindgen::bcachefs::bch_sb_handle;
|
||||
use clap::builder::PossibleValue;
|
||||
use crate::c_str;
|
||||
use anyhow::anyhow;
|
||||
use bch_bindgen::bcachefs::bch_sb_handle;
|
||||
use clap::builder::PossibleValue;
|
||||
use log::info;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum UnlockPolicy {
|
||||
@ -18,11 +21,11 @@ impl std::str::FromStr for UnlockPolicy {
|
||||
type Err = anyhow::Error;
|
||||
fn from_str(s: &str) -> anyhow::Result<Self> {
|
||||
match s {
|
||||
""|"none" => Ok(UnlockPolicy::None),
|
||||
"fail" => Ok(UnlockPolicy::Fail),
|
||||
"wait" => Ok(UnlockPolicy::Wait),
|
||||
"ask" => Ok(UnlockPolicy::Ask),
|
||||
_ => Err(anyhow!("Invalid unlock policy provided")),
|
||||
"" | "none" => Ok(UnlockPolicy::None),
|
||||
"fail" => Ok(UnlockPolicy::Fail),
|
||||
"wait" => Ok(UnlockPolicy::Wait),
|
||||
"ask" => Ok(UnlockPolicy::Ask),
|
||||
_ => Err(anyhow!("Invalid unlock policy provided")),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -152,18 +155,32 @@ fn unlock_master_key(sb: &bch_sb_handle, passphrase: &str) -> anyhow::Result<()>
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_from_passphrase_file(block_device: &bch_sb_handle, passphrase_file: &std::path::Path) -> anyhow::Result<()> {
|
||||
pub fn read_from_passphrase_file(
|
||||
block_device: &bch_sb_handle,
|
||||
passphrase_file: &std::path::Path,
|
||||
) -> anyhow::Result<()> {
|
||||
// Attempts to unlock the master key by password_file
|
||||
// Return true if unlock was successful, false otherwise
|
||||
info!("Attempting to unlock master key for filesystem {}, using password from file {}", block_device.sb().uuid(), passphrase_file.display());
|
||||
info!(
|
||||
"Attempting to unlock master key for filesystem {}, using password from file {}",
|
||||
block_device.sb().uuid(),
|
||||
passphrase_file.display()
|
||||
);
|
||||
// Read the contents of the password_file into a string
|
||||
let passphrase = fs::read_to_string(passphrase_file)?;
|
||||
// Call decrypt_master_key with the read string
|
||||
unlock_master_key(block_device, &passphrase)
|
||||
}
|
||||
|
||||
pub fn apply_key_unlocking_policy(block_device: &bch_sb_handle, unlock_policy: UnlockPolicy) -> anyhow::Result<()> {
|
||||
info!("Attempting to unlock master key for filesystem {}, using unlock policy {}", block_device.sb().uuid(), unlock_policy);
|
||||
pub fn apply_key_unlocking_policy(
|
||||
block_device: &bch_sb_handle,
|
||||
unlock_policy: UnlockPolicy,
|
||||
) -> anyhow::Result<()> {
|
||||
info!(
|
||||
"Attempting to unlock master key for filesystem {}, using unlock policy {}",
|
||||
block_device.sb().uuid(),
|
||||
unlock_policy
|
||||
);
|
||||
match unlock_policy {
|
||||
UnlockPolicy::Fail => Err(anyhow!("no passphrase available")),
|
||||
UnlockPolicy::Wait => Ok(wait_for_unlock(&block_device.sb().uuid())?),
|
||||
|
@ -1,13 +1,16 @@
|
||||
use std::path::Path;
|
||||
|
||||
use bch_bindgen::c::{bchfs_handle, BCH_IOCTL_SUBVOLUME_CREATE, BCH_IOCTL_SUBVOLUME_DESTROY, bch_ioctl_subvolume, bcache_fs_open, BCH_SUBVOL_SNAPSHOT_CREATE, bcache_fs_close};
|
||||
use bch_bindgen::c::{
|
||||
bcache_fs_close, bcache_fs_open, bch_ioctl_subvolume, bchfs_handle, BCH_IOCTL_SUBVOLUME_CREATE,
|
||||
BCH_IOCTL_SUBVOLUME_DESTROY, BCH_SUBVOL_SNAPSHOT_CREATE,
|
||||
};
|
||||
use bch_bindgen::path_to_cstr;
|
||||
use errno::Errno;
|
||||
|
||||
/// A handle to a bcachefs filesystem
|
||||
/// This can be used to send [`libc::ioctl`] to the underlying filesystem.
|
||||
pub(crate) struct BcachefsHandle {
|
||||
inner: bchfs_handle
|
||||
inner: bchfs_handle,
|
||||
}
|
||||
|
||||
impl BcachefsHandle {
|
||||
@ -16,13 +19,13 @@ impl BcachefsHandle {
|
||||
pub(crate) unsafe fn open<P: AsRef<Path>>(path: P) -> Self {
|
||||
let path = path_to_cstr(path);
|
||||
Self {
|
||||
inner: bcache_fs_open(path.as_ptr())
|
||||
inner: bcache_fs_open(path.as_ptr()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// I/O control commands that can be sent to a bcachefs filesystem
|
||||
/// Those are non-exhaustive
|
||||
/// Those are non-exhaustive
|
||||
#[repr(u32)]
|
||||
#[non_exhaustive]
|
||||
pub enum BcachefsIoctl {
|
||||
@ -39,14 +42,18 @@ pub enum BcachefsIoctlPayload {
|
||||
impl From<&BcachefsIoctlPayload> for *const libc::c_void {
|
||||
fn from(value: &BcachefsIoctlPayload) -> Self {
|
||||
match value {
|
||||
BcachefsIoctlPayload::Subvolume(p) => p as *const _ as *const libc::c_void
|
||||
BcachefsIoctlPayload::Subvolume(p) => p as *const _ as *const libc::c_void,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BcachefsHandle {
|
||||
/// Type-safe [`libc::ioctl`] for bcachefs filesystems
|
||||
pub fn ioctl(&self, request: BcachefsIoctl, payload: &BcachefsIoctlPayload) -> Result<(), Errno> {
|
||||
pub fn ioctl(
|
||||
&self,
|
||||
request: BcachefsIoctl,
|
||||
payload: &BcachefsIoctlPayload,
|
||||
) -> Result<(), Errno> {
|
||||
let payload_ptr: *const libc::c_void = payload.into();
|
||||
let ret = unsafe { libc::ioctl(self.inner.ioctl_fd, request as libc::Ioctl, payload_ptr) };
|
||||
|
||||
@ -61,41 +68,55 @@ impl BcachefsHandle {
|
||||
/// at the given path
|
||||
pub fn create_subvolume<P: AsRef<Path>>(&self, dst: P) -> Result<(), Errno> {
|
||||
let dst = path_to_cstr(dst);
|
||||
self.ioctl(BcachefsIoctl::SubvolumeCreate, &BcachefsIoctlPayload::Subvolume(bch_ioctl_subvolume {
|
||||
dirfd: libc::AT_FDCWD as u32,
|
||||
mode: 0o777,
|
||||
dst_ptr: dst.as_ptr() as u64,
|
||||
..Default::default()
|
||||
}))
|
||||
self.ioctl(
|
||||
BcachefsIoctl::SubvolumeCreate,
|
||||
&BcachefsIoctlPayload::Subvolume(bch_ioctl_subvolume {
|
||||
dirfd: libc::AT_FDCWD as u32,
|
||||
mode: 0o777,
|
||||
dst_ptr: dst.as_ptr() as u64,
|
||||
..Default::default()
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
/// Delete the subvolume at the given path
|
||||
/// for this bcachefs filesystem
|
||||
pub fn delete_subvolume<P: AsRef<Path>>(&self, dst: P) -> Result<(), Errno> {
|
||||
let dst = path_to_cstr(dst);
|
||||
self.ioctl(BcachefsIoctl::SubvolumeDestroy, &BcachefsIoctlPayload::Subvolume(bch_ioctl_subvolume {
|
||||
dirfd: libc::AT_FDCWD as u32,
|
||||
mode: 0o777,
|
||||
dst_ptr: dst.as_ptr() as u64,
|
||||
..Default::default()
|
||||
}))
|
||||
self.ioctl(
|
||||
BcachefsIoctl::SubvolumeDestroy,
|
||||
&BcachefsIoctlPayload::Subvolume(bch_ioctl_subvolume {
|
||||
dirfd: libc::AT_FDCWD as u32,
|
||||
mode: 0o777,
|
||||
dst_ptr: dst.as_ptr() as u64,
|
||||
..Default::default()
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
/// Snapshot a subvolume for this bcachefs filesystem
|
||||
/// at the given path
|
||||
pub fn snapshot_subvolume<P: AsRef<Path>>(&self, extra_flags: u32, src: Option<P>, dst: P) -> Result<(), Errno> {
|
||||
pub fn snapshot_subvolume<P: AsRef<Path>>(
|
||||
&self,
|
||||
extra_flags: u32,
|
||||
src: Option<P>,
|
||||
dst: P,
|
||||
) -> Result<(), Errno> {
|
||||
let src = src.map(|src| path_to_cstr(src));
|
||||
let dst = path_to_cstr(dst);
|
||||
|
||||
let res = self.ioctl(BcachefsIoctl::SubvolumeCreate, &BcachefsIoctlPayload::Subvolume(bch_ioctl_subvolume {
|
||||
flags: BCH_SUBVOL_SNAPSHOT_CREATE | extra_flags,
|
||||
dirfd: libc::AT_FDCWD as u32,
|
||||
mode: 0o777,
|
||||
src_ptr: src.as_ref().map_or(0, |x| x.as_ptr() as u64),
|
||||
//src_ptr: if let Some(src) = src { src.as_ptr() } else { std::ptr::null() } as u64,
|
||||
dst_ptr: dst.as_ptr() as u64,
|
||||
..Default::default()
|
||||
}));
|
||||
let res = self.ioctl(
|
||||
BcachefsIoctl::SubvolumeCreate,
|
||||
&BcachefsIoctlPayload::Subvolume(bch_ioctl_subvolume {
|
||||
flags: BCH_SUBVOL_SNAPSHOT_CREATE | extra_flags,
|
||||
dirfd: libc::AT_FDCWD as u32,
|
||||
mode: 0o777,
|
||||
src_ptr: src.as_ref().map_or(0, |x| x.as_ptr() as u64),
|
||||
//src_ptr: if let Some(src) = src { src.as_ptr() } else { std::ptr::null() } as u64,
|
||||
dst_ptr: dst.as_ptr() as u64,
|
||||
..Default::default()
|
||||
}),
|
||||
);
|
||||
|
||||
drop(src);
|
||||
drop(dst);
|
||||
|
Loading…
Reference in New Issue
Block a user