diff --git a/bcachefs.c b/bcachefs.c index 871482eb..ada7dcfc 100644 --- a/bcachefs.c +++ b/bcachefs.c @@ -203,12 +203,6 @@ int main(int argc, char *argv[]) if (!strcmp(cmd, "set-option")) return cmd_set_option(argc, argv); - if (argc < 2) { - printf("%s: missing command\n", argv[0]); - usage(); - exit(EXIT_FAILURE); - } - #if 0 if (!strcmp(cmd, "assemble")) return cmd_assemble(argc, argv); @@ -236,6 +230,8 @@ int main(int argc, char *argv[]) return cmd_dump(argc, argv); if (!strcmp(cmd, "list")) return cmd_list(argc, argv); + if (!strcmp(cmd, "rust-list")) + return cmd_rust_list(argc, argv); if (!strcmp(cmd, "list_journal")) return cmd_list_journal(argc, argv); if (!strcmp(cmd, "kill_btree_node")) diff --git a/cmd_list.c b/cmd_list.c index db66af2d..1b07df30 100644 --- a/cmd_list.c +++ b/cmd_list.c @@ -5,7 +5,6 @@ #include "cmds.h" #include "libbcachefs.h" -#include "qcow2.h" #include "tools-util.h" #include "libbcachefs/bcachefs.h" diff --git a/cmds.h b/cmds.h index 440b1966..c7a015c7 100644 --- a/cmds.h +++ b/cmds.h @@ -45,6 +45,7 @@ int cmd_fsck(int argc, char *argv[]); int cmd_dump(int argc, char *argv[]); int cmd_list(int argc, char *argv[]); +int cmd_rust_list(int argc, char *argv[]); int cmd_list_journal(int argc, char *argv[]); int cmd_kill_btree_node(int argc, char *argv[]); diff --git a/rust-src/Cargo.lock b/rust-src/Cargo.lock index 9e5fd2a5..754b1da8 100644 --- a/rust-src/Cargo.lock +++ b/rust-src/Cargo.lock @@ -87,9 +87,8 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.63.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36d860121800b2a9a94f9b5604b332d5cffb234ce17609ea479d723dbc9d3885" +version = "0.64.0" +source = "git+https://evilpiepirate.org/git/rust-bindgen.git#f773267b090bf16b9e8375fcbdcd8ba5e88806a8" dependencies = [ "bitflags", "cexpr", @@ -167,9 +166,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.4.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" +checksum = "77ed9a53e5d4d9c573ae844bfac6872b159cb1d1585a83b29e7a64b7eef7332a" dependencies = [ "glob", "libc", diff --git a/rust-src/bch_bindgen/Cargo.lock b/rust-src/bch_bindgen/Cargo.lock index dca947aa..3d17e2f4 100644 --- a/rust-src/bch_bindgen/Cargo.lock +++ b/rust-src/bch_bindgen/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" +checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" [[package]] name = "atty" @@ -54,9 +54,8 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.63.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36d860121800b2a9a94f9b5604b332d5cffb234ce17609ea479d723dbc9d3885" +version = "0.64.0" +source = "git+file:///home/kent/rust-src/rust-bindgen#f773267b090bf16b9e8375fcbdcd8ba5e88806a8" dependencies = [ "bitflags", "cexpr", @@ -134,9 +133,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.4.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" +checksum = "77ed9a53e5d4d9c573ae844bfac6872b159cb1d1585a83b29e7a64b7eef7332a" dependencies = [ "glob", "libc", @@ -171,9 +170,9 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cxx" -version = "1.0.89" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc831ee6a32dd495436e317595e639a587aa9907bef96fe6e6abc290ab6204e9" +checksum = "86d3488e7665a7a483b57e25bdd90d0aeb2bc7608c8d0346acf2ad3f1caf1d62" dependencies = [ "cc", "cxxbridge-flags", @@ -183,9 +182,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.89" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94331d54f1b1a8895cd81049f7eaaaef9d05a7dcb4d1fd08bf3ff0806246789d" +checksum = "48fcaf066a053a41a81dfb14d57d99738b767febb8b735c3016e469fac5da690" dependencies = [ "cc", "codespan-reporting", @@ -198,15 +197,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.89" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48dcd35ba14ca9b40d6e4b4b39961f23d835dbb8eed74565ded361d93e1feb8a" +checksum = "a2ef98b8b717a829ca5603af80e1f9e2e48013ab227b68ef37872ef84ee479bf" [[package]] name = "cxxbridge-macro" -version = "1.0.89" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bbeb29798b407ccd82a3324ade1a7286e0d29851475990b612670f6f5124d2" +checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892" dependencies = [ "proc-macro2", "quote", @@ -214,10 +213,31 @@ dependencies = [ ] [[package]] -name = "fastrand" -version = "1.8.0" +name = "errno" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ "instant", ] @@ -291,6 +311,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "io-lifetimes" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3" +dependencies = [ + "libc", + "windows-sys 0.45.0", +] + [[package]] name = "js-sys" version = "0.3.61" @@ -337,6 +367,12 @@ dependencies = [ "cc", ] +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + [[package]] name = "log" version = "0.4.17" @@ -398,9 +434,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "peeking_take_while" @@ -416,9 +452,9 @@ checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" [[package]] name = "proc-macro2" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" dependencies = [ "unicode-ident", ] @@ -456,21 +492,26 @@ version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - [[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustix" +version = "0.36.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.45.0", +] + [[package]] name = "scratch" version = "1.0.3" @@ -485,9 +526,9 @@ checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" [[package]] name = "syn" -version = "1.0.107" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -496,16 +537,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" dependencies = [ "cfg-if", "fastrand", - "libc", "redox_syscall", - "remove_dir_all", - "winapi", + "rustix", + "windows-sys 0.42.0", ] [[package]] @@ -667,3 +707,84 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" diff --git a/rust-src/bch_bindgen/Cargo.toml b/rust-src/bch_bindgen/Cargo.toml index ce15fe0a..0590c61a 100644 --- a/rust-src/bch_bindgen/Cargo.toml +++ b/rust-src/bch_bindgen/Cargo.toml @@ -23,4 +23,4 @@ gag = "1.0.0" [build-dependencies] pkg-config = "0.3" -bindgen = { version = "0.63", default-features = false } +bindgen = { git = "https://evilpiepirate.org/git/rust-bindgen.git", default-features = false } diff --git a/rust-src/bch_bindgen/build.rs b/rust-src/bch_bindgen/build.rs index c5f19ff0..22c9777a 100644 --- a/rust-src/bch_bindgen/build.rs +++ b/rust-src/bch_bindgen/build.rs @@ -27,6 +27,7 @@ fn main() { .clang_arg("-DZSTD_STATIC_LINKING_ONLY") .clang_arg("-DNO_BCACHEFS_FS") .clang_arg("-D_GNU_SOURCE") + .clang_arg("-fkeep-inline-functions") .derive_debug(true) .derive_default(true) .derive_eq(true) @@ -36,11 +37,12 @@ fn main() { }) .allowlist_function(".*bch2_.*") .allowlist_function("bio_.*") - .allowlist_function("bch2_super_write_fd") .allowlist_function("derive_passphrase") .allowlist_function("request_key") .allowlist_function("add_key") .allowlist_function("keyctl_search") + .allowlist_function("match_string") + .allowlist_function("printbuf.*") .blocklist_type("bch_extent_ptr") .blocklist_type("btree_node") .blocklist_type("bch_extent_crc32") @@ -48,6 +50,11 @@ fn main() { .blocklist_type("srcu_struct") .allowlist_var("BCH_.*") .allowlist_var("KEY_SPEC_.*") + .allowlist_var("bch.*") + .allowlist_var("POS_MIN") + .allowlist_var("POS_MAX") + .allowlist_var("SPOS_MAX") + .blocklist_item("bch2_bkey_ops") .allowlist_type("bch_kdf_types") .allowlist_type("bch_sb_field_.*") .allowlist_type("bch_encrypted_key") @@ -56,9 +63,14 @@ fn main() { .allowlist_function("bch2_err_str") .newtype_enum("bch_kdf_types") .opaque_type("gendisk") - .opaque_type("bkey") .opaque_type("gc_stripe") .opaque_type("open_bucket.*") + .opaque_type("replicas_delta_list") + .no_copy("btree_trans") + .no_copy("printbuf") + .no_partialeq("bkey") + .no_partialeq("bpos") + .generate_inline_functions(true) .generate() .expect("BindGen Generation Failiure: [libbcachefs_wrapper]"); bindings 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, diff --git a/rust-src/src/cmd_list.rs b/rust-src/src/cmd_list.rs new file mode 100644 index 00000000..ea4c93fa --- /dev/null +++ b/rust-src/src/cmd_list.rs @@ -0,0 +1,127 @@ +use atty::Stream; +use bch_bindgen::error; +use bch_bindgen::bcachefs; +use bch_bindgen::fs::Fs; +use bch_bindgen::btree::BtreeTrans; +use bch_bindgen::btree::BtreeIter; +use clap::Parser; +use colored::Colorize; +use std::ffi::{CStr, OsStr, c_int, c_char}; +use std::os::unix::ffi::OsStrExt; + +fn list_keys(fs: &Fs, opt: Cli) -> anyhow::Result<()> { + let trans = BtreeTrans::new(fs); + let mut iter = BtreeIter::new(&trans, opt.btree, opt.start, 1 << 11); + + while let Some(k) = iter.peek_and_restart()? { + unsafe { + if (*k.k).p > opt.end { + break; + } + } + + println!("{}", k.to_text(fs)); + + iter.advance(); + } + + Ok(()) +} + +fn list_btree_formats(fs: &Fs, opt: Cli) -> anyhow::Result<()> { + let trans = BtreeTrans::new(fs); + + Ok(()) +} + +fn list_btree_nodes(fs: &Fs, opt: Cli) -> anyhow::Result<()> { + let trans = BtreeTrans::new(fs); + + Ok(()) +} + +fn list_nodes_ondisk(fs: &Fs, opt: Cli) -> anyhow::Result<()> { + let trans = BtreeTrans::new(fs); + + Ok(()) +} + +fn list_nodes_keys(fs: &Fs, opt: Cli) -> anyhow::Result<()> { + let trans = BtreeTrans::new(fs); + + Ok(()) +} + +#[derive(Clone, clap::ValueEnum)] +enum Mode { + Keys, + Formats, + Nodes, + NodesOndisk, + NodesKeys, +} + +#[derive(Parser)] +struct Cli { + /// Btree to list from + #[arg(short, long, default_value_t=bcachefs::btree_id::BTREE_ID_extents)] + btree: bcachefs::btree_id, + + /// Btree depth to descend to (0 == leaves) + #[arg(short, long, default_value_t=0)] + level: u8, + + /// Start position to list from + #[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="keys")] + mode: Mode, + + /// Check (fsck) the filesystem first + #[arg(short, long, default_value_t=false)] + fsck: bool, + + /// Force color on/off. Default: autodetect tty + #[arg(short, long, action = clap::ArgAction::Set, default_value_t=atty::is(Stream::Stdout))] + colorize: bool, + + /// Verbose mode + #[arg(short, long, action = clap::ArgAction::Count)] + verbose: u8, + + #[arg(required(true))] + devices: Vec<std::path::PathBuf>, +} + +fn cmd_list_inner(opt: Cli) -> anyhow::Result<()> { + let fs_opts: bcachefs::bch_opts = Default::default(); + + 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::NodesKeys => list_nodes_keys(&fs, opt), + } +} + +#[no_mangle] +pub extern "C" fn cmd_rust_list(argc: c_int, argv: *const *const c_char) { + let argv: Vec<_> = (0..argc) + .map(|i| unsafe { CStr::from_ptr(*argv.add(i as usize)) }) + .map(|i| OsStr::from_bytes(i.to_bytes())) + .collect(); + + let opt = Cli::parse_from(argv); + colored::control::set_override(opt.colorize); + if let Err(e) = cmd_list_inner(opt) { + error!("Fatal error: {}", e); + } +} diff --git a/rust-src/src/cmd_mount.rs b/rust-src/src/cmd_mount.rs index 4bbe5fe7..1251d0d7 100644 --- a/rust-src/src/cmd_mount.rs +++ b/rust-src/src/cmd_mount.rs @@ -125,14 +125,6 @@ fn get_devices_by_uuid(uuid: Uuid) -> anyhow::Result<Vec<(PathBuf, bch_sb_handle Ok(devs) } -fn stdout_isatty() -> &'static str { - if atty::is(Stream::Stdout) { - "true" - } else { - "false" - } -} - /// Mount a bcachefs filesystem by its UUID. #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] @@ -159,10 +151,11 @@ struct Cli { options: String, /// Force color on/off. Default: autodetect tty - #[arg(short, long, action = clap::ArgAction::Set, default_value=stdout_isatty())] + #[arg(short, long, action = clap::ArgAction::Set, default_value_t=atty::is(Stream::Stdout))] colorize: bool, - #[arg(short = 'v', long, action = clap::ArgAction::Count)] + /// Verbose mode + #[arg(short, long, action = clap::ArgAction::Count)] verbose: u8, } diff --git a/rust-src/src/filesystem.rs b/rust-src/src/filesystem.rs deleted file mode 100644 index 336f847e..00000000 --- a/rust-src/src/filesystem.rs +++ /dev/null @@ -1,9 +0,0 @@ -extern "C" { - pub static stdout: *mut libc::FILE; -} -use bch_bindgen::{debug, info}; -use colored::Colorize; -use getset::{CopyGetters, Getters}; -use std::path::PathBuf; -use bcachefs::bch_sb_handle; - diff --git a/rust-src/src/lib.rs b/rust-src/src/lib.rs index 5feaa2e9..a33e3914 100644 --- a/rust-src/src/lib.rs +++ b/rust-src/src/lib.rs @@ -1,15 +1,6 @@ pub mod key; pub mod cmd_mount; - -pub mod err { - pub enum GError { - Unknown { - message: std::borrow::Cow<'static, String>, - }, - } - pub type GResult<T, E, OE> = ::core::result::Result<::core::result::Result<T, E>, OE>; - pub type Result<T, E> = GResult<T, E, GError>; -} +pub mod cmd_list; #[macro_export] macro_rules! c_str {