aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2023-02-26 21:38:12 -0500
committerKent Overstreet <kent.overstreet@linux.dev>2023-02-27 21:45:42 -0500
commite0e06d95f899e5e83d66e94600928156a5eb3a4b (patch)
tree5de00419aeed9689125493ce6894ab90b5ea57a0
parent30cca2e94d0dfa8c3151daf1393f402d32bb9407 (diff)
downloadbcachefs-tools-e0e06d95f899e5e83d66e94600928156a5eb3a4b.tar.gz
Rust: Start of cmd_list rewrite
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>
-rw-r--r--bcachefs.c8
-rw-r--r--cmd_list.c1
-rw-r--r--cmds.h1
-rw-r--r--rust-src/Cargo.lock9
-rw-r--r--rust-src/bch_bindgen/Cargo.lock195
-rw-r--r--rust-src/bch_bindgen/Cargo.toml2
-rw-r--r--rust-src/bch_bindgen/build.rs16
-rw-r--r--rust-src/bch_bindgen/src/btree.rs80
-rw-r--r--rust-src/bch_bindgen/src/errcode.rs40
-rw-r--r--rust-src/bch_bindgen/src/fs.rs30
-rw-r--r--rust-src/bch_bindgen/src/lib.rs172
-rw-r--r--rust-src/bch_bindgen/src/libbcachefs_wrapper.h1
-rw-r--r--rust-src/bch_bindgen/src/rs.rs10
-rw-r--r--rust-src/src/cmd_list.rs127
-rw-r--r--rust-src/src/cmd_mount.rs13
-rw-r--r--rust-src/src/filesystem.rs9
-rw-r--r--rust-src/src/lib.rs11
17 files changed, 635 insertions, 90 deletions
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 = "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",
]
@@ -292,6 +312,16 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -338,6 +368,12 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -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",
]
@@ -457,21 +493,26 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -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 {