]> git.sesse.net Git - bcachefs-tools-debian/commitdiff
Rust: Start of cmd_list rewrite
authorKent Overstreet <kent.overstreet@linux.dev>
Mon, 27 Feb 2023 02:38:12 +0000 (21:38 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Tue, 28 Feb 2023 02:45:42 +0000 (21:45 -0500)
This is a _very_ preliminary rewrite of the cmd_list tool in rust, which
is intended to be a testing ground for a safe interface in Rust to the
core btree interface. This adds rust wrappers for:

bch_fs: provides bch2_fs_open(), bch2_fs_stop
btree_trans: provides bch2_trans_init(), bch2_trans_exit()
btree_iter: provides peek, peek_and_restart, advance
bch_errcode: implements Display (wraps bch2_err_str())
bpos: implements Ord (wraps bpos_cmp())
bkey_s_c: implements Display (wraps bch2_bkey_val_to_text())

and other assorted types.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
17 files changed:
bcachefs.c
cmd_list.c
cmds.h
rust-src/Cargo.lock
rust-src/bch_bindgen/Cargo.lock
rust-src/bch_bindgen/Cargo.toml
rust-src/bch_bindgen/build.rs
rust-src/bch_bindgen/src/btree.rs [new file with mode: 0644]
rust-src/bch_bindgen/src/errcode.rs [new file with mode: 0644]
rust-src/bch_bindgen/src/fs.rs [new file with mode: 0644]
rust-src/bch_bindgen/src/lib.rs
rust-src/bch_bindgen/src/libbcachefs_wrapper.h
rust-src/bch_bindgen/src/rs.rs
rust-src/src/cmd_list.rs [new file with mode: 0644]
rust-src/src/cmd_mount.rs
rust-src/src/filesystem.rs [deleted file]
rust-src/src/lib.rs

index 871482eb2848728496761ce89c622ff370636cb4..ada7dcfcbd93c1d642e52d5da20230e08243ceb2 100644 (file)
@@ -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"))
index db66af2de175bd4d6a595c083baf58407fb21af6..1b07df3019733dd2ee5b0c83ba6b3a731eb9b049 100644 (file)
@@ -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 440b1966c21a6a7f633abed61f64ed9f482d70ac..c7a015c77fef6e74a466e01a3eeae869648e089c 100644 (file)
--- 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[]);
 
index 9e5fd2a5148a62444f34850df52be2ecf53a4ecc..754b1da8314e850505c223d97957af0935f609de 100644 (file)
@@ -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",
index dca947aa94a8b00de097b9bff8e37e9916bf8383..3d17e2f42ad98e6e11315d2292d19e5a931ae075 100644 (file)
@@ -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,26 +197,47 @@ 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",
  "syn",
 ]
 
+[[package]]
+name = "errno"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+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.8.0"
+version = "1.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
+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"
index ce15fe0a3c36c0f6d1fbdc90c1422a6b17c5f9b5..0590c61a5d3fd1e4ffb974ee6a30490322cfcc99 100644 (file)
@@ -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 }
index c5f19ff010ffac15a10cdf4fbd45b2edf1bb9cb2..22c9777a63cfb3b6499e9d490844b1902b1baf84 100644 (file)
@@ -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 (file)
index 0000000..da9dbca
--- /dev/null
@@ -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 (file)
index 0000000..4d75f1d
--- /dev/null
@@ -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 (file)
index 0000000..1176846
--- /dev/null
@@ -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) }
+    }             
+}
index c54786aaed62822edc39864e50634d78f4ee8a8e..a5f5a0d57f48a4e1946cb4a43457f9bf89afbbca 100644 (file)
@@ -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 }
+    }
+}
index ec2b5850d3fe7f1cfa3a53d57c0973f8fa99c34d..6332d9576a144afe154ab14c076e56dba6225c15 100644 (file)
@@ -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"
index 17610f3a7f2cbc7c46ddda4135fb37fb08a5d3b7..24594ae16022f2b50823ce7b30e37bf64c57f25f 100644 (file)
@@ -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 (file)
index 0000000..ea4c93f
--- /dev/null
@@ -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);
+    }
+}
index 4bbe5fe7a2d5f2dc973e4fb5ba4f888b7528d1b7..1251d0d735c9cfc2d62f124782d5abfbef5a2584 100644 (file)
@@ -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 (file)
index 336f847..0000000
+++ /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;
-
index 5feaa2e9ea0a0ffa16f70c7134afe4aa3043d778..a33e3914817af23b8a6de783ed9acf9f135d7a7c 100644 (file)
@@ -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 {