diff --git a/Cargo.lock b/Cargo.lock index 2c5ccfc..37827b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -178,6 +178,15 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "arc-swap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207" +dependencies = [ + "rustversion", +] + [[package]] name = "argon2" version = "0.5.3" @@ -210,7 +219,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -335,7 +344,7 @@ checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -421,7 +430,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn", + "syn 2.0.117", ] [[package]] @@ -585,6 +594,15 @@ dependencies = [ "crossbeam-queue", ] +[[package]] +name = "caps" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd1ddba47aba30b6a889298ad0109c3b8dcb0e8fc993b459daa7067d46f865e0" +dependencies = [ + "libc", +] + [[package]] name = "cbc" version = "0.1.2" @@ -738,7 +756,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -860,6 +878,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crc64" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2707e3afba5e19b75d582d88bc79237418f2a2a2d673d01cf9b03633b46e98f3" + [[package]] name = "crossbeam-channel" version = "0.5.15" @@ -1032,7 +1056,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -1073,7 +1097,7 @@ dependencies = [ "http-body", "http-body-util", "libc", - "log 0.4.29", + "log", "lru", "mime_guess", "parking_lot", @@ -1087,6 +1111,19 @@ dependencies = [ "xmltree", ] +[[package]] +name = "dbs-snapshot" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0315cb247b6726d92c74b955b7d79b4be475be58335fee120f19292740132eb1" +dependencies = [ + "displaydoc", + "libc", + "thiserror 1.0.69", + "versionize", + "versionize_derive", +] + [[package]] name = "delegate" version = "0.13.5" @@ -1095,7 +1132,7 @@ checksum = "780eb241654bf097afb00fc5f054a09b687dad862e485fdcf8399bb056565370" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -1137,7 +1174,7 @@ checksum = "d08b3a0bcc0d079199cd476b2cae8435016ec11d1c0986c6901c5ac223041534" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -1212,7 +1249,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -1375,6 +1412,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + [[package]] name = "enum_dispatch" version = "0.3.13" @@ -1384,7 +1427,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -1402,7 +1445,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eef" dependencies = [ - "log 0.4.29", + "log", "regex", ] @@ -1422,7 +1465,7 @@ dependencies = [ "anstyle", "env_filter", "jiff", - "log 0.4.29", + "log", ] [[package]] @@ -1543,7 +1586,7 @@ version = "0.1.0" dependencies = [ "anyhow", "chrono", - "log 0.4.29", + "log", "rusqlite", "serde", "serde_json", @@ -1645,16 +1688,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] -name = "fuse" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e57070510966bfef93662a81cb8aa2b1c7db0964354fa9921434f04b9e8660" +name = "fuse-backend-rs" +version = "0.14.0" dependencies = [ + "arc-swap", + "async-trait", + "bitflags 1.3.2", + "caps", + "core-foundation-sys", + "dbs-snapshot", + "io-uring", + "lazy_static", "libc", - "log 0.3.9", - "pkg-config", - "thread-scoped", - "time 0.1.45", + "log", + "mio 0.8.11", + "nix 0.24.3", + "radix_trie", + "tokio", + "tokio-test", + "tokio-uring", + "versionize", + "versionize_derive", + "vhost", + "virtio-bindings", + "virtio-queue", + "vm-memory", + "vmm-sys-util 0.15.0", ] [[package]] @@ -1713,7 +1772,7 @@ checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -2115,7 +2174,7 @@ dependencies = [ "core-foundation-sys", "iana-time-zone-haiku", "js-sys", - "log 0.4.29", + "log", "wasm-bindgen", "windows-core 0.62.2", ] @@ -2320,6 +2379,16 @@ dependencies = [ "rand_core 0.10.1", ] +[[package]] +name = "io-uring" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd1e1a01cfb924fd8c5c43b6827965db394f5a3a16c599ce03452266e1cf984c" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -2348,7 +2417,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4603d3033e49e2b0e31229fcab20a5d40089c607d975cd9c80551dc69eed9102" dependencies = [ "jiff-static", - "log 0.4.29", + "log", "portable-atomic", "portable-atomic-util", "serde_core", @@ -2362,7 +2431,7 @@ checksum = "782d32378dddf207193ac91cefb848ad41abb58195c95168e1291227a0832b47" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -2526,15 +2595,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "log" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" -dependencies = [ - "log 0.4.29", -] - [[package]] name = "log" version = "0.4.29" @@ -2603,7 +2663,7 @@ dependencies = [ "flate2", "futures-util", "hmac 0.12.1", - "log 0.4.29", + "log", "markbase-webdav", "md5 0.8.0", "pulldown-cmark", @@ -2658,13 +2718,14 @@ dependencies = [ "anyhow", "clap", "filetree", - "fuse", + "fuse-backend-rs", "libc", - "log 0.4.29", + "log", "rusqlite", "serde", "serde_json", - "time 0.3.47", + "time", + "vm-memory", ] [[package]] @@ -2788,6 +2849,15 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + [[package]] name = "mime" version = "0.3.17" @@ -2820,6 +2890,18 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "log", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.48.0", +] + [[package]] name = "mio" version = "1.2.0" @@ -2889,6 +2971,27 @@ dependencies = [ "tracing", ] +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[package]] +name = "nix" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset", +] + [[package]] name = "nix" version = "0.31.3" @@ -2918,7 +3021,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2de419e64947cd8830e66beb584acc3fb42ed411d103e3c794dda355d1b374b5" dependencies = [ "chrono", - "time 0.3.47", + "time", ] [[package]] @@ -2999,7 +3102,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -3239,7 +3342,7 @@ dependencies = [ "bytes", "delegate", "futures", - "log 0.4.29", + "log", "rand 0.8.6", "thiserror 1.0.69", "tokio", @@ -3257,7 +3360,7 @@ dependencies = [ "bytes", "delegate", "futures", - "log 0.4.29", + "log", "rand 0.10.1", "sha2 0.11.0", "thiserror 2.0.18", @@ -3619,7 +3722,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn", + "syn 2.0.117", ] [[package]] @@ -3703,6 +3806,16 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + [[package]] name = "rand" version = "0.4.6" @@ -3996,7 +4109,7 @@ dependencies = [ "inout 0.2.2", "internal-russh-num-bigint", "keccak", - "log 0.4.29", + "log", "md5 0.8.0", "ml-kem", "module-lattice", @@ -4050,8 +4163,8 @@ version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "443f6bbcfacb34a1aab2b12b99bf08e0c63abdc5a0db261901365df9d57fff51" dependencies = [ - "log 0.4.29", - "nix", + "log", + "nix 0.31.3", "ssh-encoding 0.3.0-rc.9", "windows-sys 0.61.2", ] @@ -4081,7 +4194,7 @@ dependencies = [ "home", "inout 0.1.4", "internal-russh-forked-ssh-key", - "log 0.4.29", + "log", "md5 0.7.0", "num-integer", "p256 0.13.2", @@ -4122,7 +4235,7 @@ dependencies = [ "chrono", "dashmap", "gloo-timers", - "log 0.4.29", + "log", "serde", "serde_bytes", "thiserror 2.0.18", @@ -4163,7 +4276,7 @@ dependencies = [ "bytes", "crc32c", "env_logger", - "log 0.4.29", + "log", "serde", "serde_json", "thiserror 2.0.18", @@ -4236,6 +4349,12 @@ dependencies = [ "cipher 0.5.2", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" @@ -4336,7 +4455,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -4545,7 +4664,7 @@ dependencies = [ "fnv", "fs2", "inline-array", - "log 0.4.29", + "log", "pagetable", "parking_lot", "rayon", @@ -4561,6 +4680,16 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "socket2" version = "0.6.3" @@ -4737,6 +4866,17 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.117" @@ -4762,7 +4902,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -4825,7 +4965,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -4836,24 +4976,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn", -] - -[[package]] -name = "thread-scoped" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcbb6aa301e5d3b0b5ef639c9a9c7e2f1c944f177b460c04dc24c69b1fa2bd99" - -[[package]] -name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", + "syn 2.0.117", ] [[package]] @@ -4919,11 +5042,11 @@ checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" dependencies = [ "bytes", "libc", - "mio", + "mio 1.2.0", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.6.3", "tokio-macros", "windows-sys 0.61.2", ] @@ -4936,7 +5059,7 @@ checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -4951,7 +5074,7 @@ dependencies = [ "fallible-iterator 0.2.0", "futures-channel", "futures-util", - "log 0.4.29", + "log", "parking_lot", "percent-encoding", "phf", @@ -4959,7 +5082,7 @@ dependencies = [ "postgres-protocol", "postgres-types", "rand 0.10.1", - "socket2", + "socket2 0.6.3", "tokio", "tokio-util", "whoami", @@ -4988,6 +5111,20 @@ dependencies = [ "tokio-stream", ] +[[package]] +name = "tokio-uring" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d5e02bb137e030b3a547c65a3bd2f1836d66a97369fdcc69034002b10e155ef" +dependencies = [ + "io-uring", + "libc", + "scoped-tls", + "slab", + "socket2 0.4.10", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.18" @@ -5077,7 +5214,7 @@ version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ - "log 0.4.29", + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -5091,7 +5228,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -5237,6 +5374,7 @@ checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" dependencies = [ "getrandom 0.4.2", "js-sys", + "rand 0.10.1", "wasm-bindgen", ] @@ -5252,6 +5390,34 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "versionize" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62929d59c7f6730b7298fcb363760550f4db6e353fbac4076d447d0e82799d6d" +dependencies = [ + "bincode", + "crc64", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "syn 1.0.109", + "versionize_derive", + "vmm-sys-util 0.12.1", +] + +[[package]] +name = "versionize_derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c4971c07ef708cd51003222e509aaed8eae14aeb2907706b01578843195e03a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "vfs" version = "0.12.2" @@ -5262,10 +5428,67 @@ dependencies = [ ] [[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" +name = "vhost" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "c76d90ce3c6b37d610a5304c9a445cfff580cf8b4b9fd02fb256aaf68552c28a" +dependencies = [ + "bitflags 2.11.1", + "libc", + "uuid", + "vm-memory", + "vmm-sys-util 0.15.0", +] + +[[package]] +name = "virtio-bindings" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "091f1f09cfbf2a78563b562e7a949465cce1aef63b6065645188d995162f8868" + +[[package]] +name = "virtio-queue" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e358084f32ed165fddb41d98ff1b7ff3c08b9611d8d6114a1b422e2e85688baf" +dependencies = [ + "libc", + "log", + "virtio-bindings", + "vm-memory", + "vmm-sys-util 0.15.0", +] + +[[package]] +name = "vm-memory" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f39348a049689cabd3377cdd9182bf526ec76a6f823b79903896452e9d7a7380" +dependencies = [ + "libc", + "thiserror 2.0.18", + "winapi", +] + +[[package]] +name = "vmm-sys-util" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1435039746e20da4f8d507a72ee1b916f7b4b05af7a91c093d2c6561934ede" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + +[[package]] +name = "vmm-sys-util" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "506c62fdf617a5176827c2f9afbcf1be155b03a9b4bf9617a60dbc07e3a1642f" +dependencies = [ + "bitflags 1.3.2", + "libc", +] [[package]] name = "wasi" @@ -5351,7 +5574,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn", + "syn 2.0.117", "wasm-bindgen-shared", ] @@ -5531,7 +5754,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -5542,7 +5765,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -5553,7 +5776,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -5564,7 +5787,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -5828,7 +6051,7 @@ dependencies = [ "heck", "indexmap", "prettyplease", - "syn", + "syn 2.0.117", "wasm-metadata", "wit-bindgen-core", "wit-component", @@ -5844,7 +6067,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn", + "syn 2.0.117", "wit-bindgen-core", "wit-bindgen-rust", ] @@ -5858,7 +6081,7 @@ dependencies = [ "anyhow", "bitflags 2.11.1", "indexmap", - "log 0.4.29", + "log", "serde", "serde_derive", "serde_json", @@ -5877,7 +6100,7 @@ dependencies = [ "anyhow", "id-arena", "indexmap", - "log 0.4.29", + "log", "semver", "serde", "serde_derive", @@ -5966,7 +6189,7 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", "synstructure", ] @@ -5987,7 +6210,7 @@ checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -6007,7 +6230,7 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", "synstructure", ] @@ -6028,7 +6251,7 @@ checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -6061,7 +6284,7 @@ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -6080,7 +6303,7 @@ dependencies = [ "hmac 0.12.1", "pbkdf2 0.11.0", "sha1 0.10.6", - "time 0.3.47", + "time", "zstd 0.11.2+zstd.1.5.2", ] diff --git a/markbase-fuse/Cargo.toml b/markbase-fuse/Cargo.toml index 55f42d6..a743140 100644 --- a/markbase-fuse/Cargo.toml +++ b/markbase-fuse/Cargo.toml @@ -18,10 +18,11 @@ path = "src/lib.rs" anyhow = "1" clap = { version = "4", features = ["derive"] } filetree = { path = "../filetree" } -fuse = "0.3.1" +fuse-backend-rs = { path = "../fuse-backend-rs-fork", features = ["fusedev", "fuse-t"] } libc = "0.2" log = "0.4" rusqlite = { version = "0.32", features = ["bundled"] } serde = { version = "1", features = ["derive"] } serde_json = "1" time = "0.3" +vm-memory = "0.17" diff --git a/markbase-fuse/build.rs b/markbase-fuse/build.rs index 35c09ef..6908fda 100644 --- a/markbase-fuse/build.rs +++ b/markbase-fuse/build.rs @@ -1,13 +1,16 @@ fn main() { - // Manual linking for FUSE-T on macOS (no pkg-config dependency) - println!("cargo:rustc-link-search=native=/usr/local/lib"); - - // Link to both fuse3 and fuse-t (FUSE-T provides both) - println!("cargo:rustc-link-lib=dylib=fuse3"); - println!("cargo:rustc-link-lib=dylib=fuse-t"); - - // Set rpath for runtime loading - println!("cargo:rustc-link-arg=-Wl,-rpath,/usr/local/lib"); - - println!("cargo:rerun-if-changed=build.rs"); -} + if cfg!(target_os = "macos") { + // Link fuse-t library + println!("cargo:rustc-link-lib=fuse-t"); + + // Link macOS frameworks + println!("cargo:rustc-link-lib=framework=DiskArbitration"); + println!("cargo:rustc-link-lib=framework=CoreFoundation"); + + // Add fuse-t include path + println!("cargo:rustc-link-search=native=/usr/local/lib"); + + // Rerun if fuse-t changes + println!("cargo:rerun-if-changed=/usr/local/lib/libfuse-t.dylib"); + } +} \ No newline at end of file diff --git a/markbase-fuse/src/fuse/db.rs b/markbase-fuse/src/fuse/db.rs index 3ff6964..76522a5 100644 --- a/markbase-fuse/src/fuse/db.rs +++ b/markbase-fuse/src/fuse/db.rs @@ -106,6 +106,21 @@ impl DbManager { Ok(labels) } + pub fn find_node_id_by_parent(&self, parent_id: &str, name: &str) -> Result> { + let conn = self.conn.lock().unwrap(); + + let sql = "SELECT node_id FROM file_nodes WHERE parent_id = ?1 AND label = ?2 AND tree_type = ?3 LIMIT 1"; + let mut stmt = conn.prepare(sql)?; + + let result = stmt.query_row(params![parent_id, name, &self.tree_type], |row| row.get::<_, String>(0)); + + match result { + Ok(node_id) => Ok(Some(node_id)), + Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None), + Err(e) => Err(e.into()), + } + } + pub fn preload_files( &self, cache: &super::cache::ThreadSafeCache, diff --git a/markbase-fuse/src/fuse/filesystem.rs b/markbase-fuse/src/fuse/filesystem.rs index 81ae3c8..98c7824 100644 --- a/markbase-fuse/src/fuse/filesystem.rs +++ b/markbase-fuse/src/fuse/filesystem.rs @@ -1,28 +1,25 @@ use anyhow::Result; -use fuse::{ - FileAttr, FileType, Filesystem, ReplyAttr, ReplyData, ReplyDirectory, ReplyEntry, Request, -}; -use libc::{EIO, ENOENT}; +use fuse_backend_rs::api::filesystem::{Context, DirEntry, Entry, FileSystem, ZeroCopyWriter}; +use fuse_backend_rs::abi::fuse_abi::{stat64, statvfs64, FsOptions, OpenOptions}; use std::collections::HashMap; +use std::ffi::CStr; use std::fs::File; -use std::io::{Read, SeekFrom}; -use std::path::Path; -use std::sync::Arc; -use std::time::SystemTime; +use std::io::{Read, Seek, SeekFrom}; +use std::os::unix::io::{AsRawFd, FromRawFd}; +use std::sync::{Arc, RwLock}; +use std::time::{Duration, SystemTime}; -use std::ffi::CString; +use super::cache::ThreadSafeCache; +use super::db::DbManager; -const TTL: std::time::Duration = std::time::Duration::from_secs(1); -const READ_CHUNK_SIZE: usize = 524288; // 512KB for maximum throughput - -const CACHE_SIZE: usize = 1000; +const TTL: Duration = Duration::from_secs(1); +const READ_CHUNK_SIZE: usize = 524288; // 512KB pub struct MarkBaseFs { db: Arc, cache: Arc, - inode_map: HashMap, - path_cache: HashMap, - next_inode: u64, + inode_map: RwLock>, + next_inode: RwLock, } impl MarkBaseFs { @@ -30,213 +27,253 @@ impl MarkBaseFs { let db = DbManager::open(db_path, tree_type)?; let cache = ThreadSafeCache::new(); - let count = db.preload_files(&cache, CACHE_SIZE)?; - println!("Pre-cached {} files for tree_type: {}", count, tree_type); - Ok(Self { db: Arc::new(db), cache: Arc::new(cache), - inode_map: HashMap::new(), - path_cache: HashMap::new(), - next_inode: 2, + inode_map: RwLock::new(HashMap::new()), + next_inode: RwLock::new(2), }) } fn find_node_id_by_inode(&self, ino: u64) -> Option { - self.inode_map.get(&ino).cloned() + self.inode_map.read().unwrap().get(&ino).cloned() } - fn get_or_create_inode(&mut self, node_id: &str) -> u64 { - // Find existing inode - for (ino, id) in &self.inode_map { + fn get_or_create_inode(&self, node_id: &str) -> u64 { + let map = self.inode_map.read().unwrap(); + for (ino, id) in &*map { if id == node_id { return *ino; } } + drop(map); - // Create new inode - let ino = self.next_inode; - self.next_inode += 1; - self.inode_map.insert(ino, node_id.to_string()); + let mut next = self.next_inode.write().unwrap(); + let ino = *next; + *next += 1; + + let mut map = self.inode_map.write().unwrap(); + map.insert(ino, node_id.to_string()); ino } - fn find_node_id_by_path(&self, path: &str) -> Option { - // Check path cache first - if let Some(node_id) = self.cache.lookup_path(path) { - return Some(node_id); - } - - // Query from database - match self.db.find_node_id(path) { - Ok(Some(node_id)) => { - self.cache.insert_path(path, &node_id); - Some(node_id) - } - _ => None, - } - } - - fn get_file_path(&self, node_id: &str) -> Option { - // Check cache first - if let Some((path, _)) = self.cache.lookup_file(node_id) { - return Some(path); - } - - // Query from database - match self.db.get_file_path(node_id) { - Ok(Some(path)) => { - self.cache.insert_file(node_id, &path, 0); - Some(path) - } - _ => None, - } - } - - fn make_file_attr(ino: u64, node_type: &str, file_size: u64) -> FileAttr { - FileAttr { - ino, - size: file_size, - blocks: (file_size + 511) / 512, - atime: SystemTime::now(), - mtime: SystemTime::now(), - ctime: SystemTime::now(), - crtime: SystemTime::now(), - kind: if node_type == "folder" { - FileType::Directory - } else { - FileType::RegularFile - }, - perm: if node_type == "folder" { 0o755 } else { 0o644 }, - nlink: if node_type == "folder" { 2 } else { 1 }, - uid: 501, // default user - gid: 20, // default group - rdev: 0, - flags: 0, - } + fn make_stat64(node_type: &str, file_size: u64) -> stat64 { + let mut st = unsafe { std::mem::zeroed::() }; + st.st_ino = 0; + st.st_mode = if node_type == "folder" { 0o755 } else { 0o644 }; + st.st_nlink = if node_type == "folder" { 2 } else { 1 }; + st.st_uid = 501; + st.st_gid = 20; + st.st_size = file_size as i64; + st.st_blocks = ((file_size + 511) / 512) as i64; + st.st_blksize = 4096; + + let now = SystemTime::now(); + st.st_atime = now.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs() as i64; + st.st_mtime = st.st_atime; + st.st_ctime = st.st_atime; + + st } } -impl Filesystem for MarkBaseFs { - fn lookup(&mut self, _req: &Request, parent: u64, name: &Path, reply: ReplyEntry) { - let parent_path = if parent == 1 { "/" } else { "" }; - let full_path = format!("{}/{}", parent_path, name.to_string_lossy()); +impl FileSystem for MarkBaseFs { + type Inode = u64; + type Handle = u64; - let node_id = self.find_node_id_by_path(&full_path); + fn init(&self, capable: FsOptions) -> std::io::Result { + Ok(capable) + } + + fn lookup( + &self, + ctx: &Context, + parent: Self::Inode, + name: &CStr, + ) -> std::io::Result { + let name_str = name.to_string_lossy(); + + let node_id = if parent == 1 { + self.db.find_node_id(&format!("/{}", name_str)).ok().flatten() + } else { + let parent_id = self.find_node_id_by_inode(parent); + match parent_id { + Some(pid) => self.db.find_node_id_by_parent(&pid, &name_str).ok().flatten(), + None => None, + } + }; match node_id { Some(id) => { - let info = self.db.get_node_info(&id).ok(); - + let info = self.db.get_node_info(&id); match info { - Some((node_type, file_size)) => { + Ok(Some((node_type, file_size))) => { let ino = self.get_or_create_inode(&id); - let attr = self.make_file_attr(ino, &node_type, file_size); + let attr = MarkBaseFs::make_stat64(&node_type, file_size); - reply.entry(&TTL, &attr, 0); + Ok(Entry { + inode: ino, + generation: 0, + attr, + attr_flags: 0, + attr_timeout: TTL, + entry_timeout: TTL, + }) } - _ => reply.error(ENOENT), + _ => Err(std::io::Error::from_raw_os_error(libc::ENOENT)), } } - None => reply.error(ENOENT), + None => Err(std::io::Error::from_raw_os_error(libc::ENOENT)), } } - fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) { - if ino == 1 { - let attr = self.make_file_attr(1, "folder", 0); - reply.attr(&TTL, &attr); - return; + fn forget(&self, ctx: &Context, inode: Self::Inode, count: u64) { + let mut map = self.inode_map.write().unwrap(); + map.remove(&inode); + } + + fn getattr( + &self, + ctx: &Context, + inode: Self::Inode, + handle: Option, + ) -> std::io::Result<(stat64, Duration)> { + if inode == 1 { + let attr = MarkBaseFs::make_stat64("folder", 0); + return Ok((attr, TTL)); } - let node_id = self.find_node_id_by_inode(ino); - + let node_id = self.find_node_id_by_inode(inode); match node_id { Some(id) => { - let info = self.db.get_node_info(&id).ok(); - + let info = self.db.get_node_info(&id); match info { - Some((node_type, file_size)) => { - let attr = self.make_file_attr(ino, &node_type, file_size); - reply.attr(&TTL, &attr); + Ok(Some((node_type, file_size))) => { + let attr = MarkBaseFs::make_stat64(&node_type, file_size); + Ok((attr, TTL)) } - _ => reply.error(ENOENT), + _ => Err(std::io::Error::from_raw_os_error(libc::ENOENT)), } } - None => reply.error(ENOENT), + None => Err(std::io::Error::from_raw_os_error(libc::ENOENT)), } } + fn open( + &self, + ctx: &Context, + inode: Self::Inode, + flags: u32, + fuse_flags: u32, + ) -> std::io::Result<(Option, OpenOptions, Option)> { + Ok((Some(inode), OpenOptions::empty(), None)) + } + fn read( - &mut self, - _req: &Request, - ino: u64, - fh: u64, - offset: i64, + &self, + ctx: &Context, + inode: Self::Inode, + handle: Self::Handle, + w: &mut dyn ZeroCopyWriter, size: u32, - reply: ReplyData, - ) { - let node_id = self.find_node_id_by_inode(ino); - + offset: u64, + lock_owner: Option, + flags: u32, + ) -> std::io::Result { + let node_id = self.find_node_id_by_inode(inode); match node_id { Some(id) => { - let file_path = self.get_file_path(&id); - + let file_path = self.db.get_file_path(&id); match file_path { - Some(fp) => { - let mut file = File::open(&fp)?; - file.seek(SeekFrom::Start(offset as u64)).ok(); - - let mut buffer = vec![0u8; size as usize]; - let bytes_read = file.read(&mut buffer).ok(); - buffer.truncate(bytes_read); - reply.data(&buffer); + Ok(Some(fp)) => { + let file = File::open(&fp)?; + let fd = file.as_raw_fd(); + let f = unsafe { File::from_raw_fd(fd) }; + let mut f = std::mem::ManuallyDrop::new(f); + + w.write_from(&mut *f, size as usize, offset) } - None => reply.error(ENOENT), + _ => Err(std::io::Error::from_raw_os_error(libc::ENOENT)), } } - None => reply.error(ENOENT), + None => Err(std::io::Error::from_raw_os_error(libc::ENOENT)), } } + fn release( + &self, + ctx: &Context, + inode: Self::Inode, + flags: u32, + handle: Self::Handle, + flush: bool, + flock_release: bool, + lock_owner: Option, + ) -> std::io::Result<()> { + Ok(()) + } + + fn opendir( + &self, + ctx: &Context, + inode: Self::Inode, + flags: u32, + ) -> std::io::Result<(Option, OpenOptions)> { + Ok((Some(inode), OpenOptions::empty())) + } + fn readdir( - &mut self, - _req: &Request, - ino: u64, - fh: u64, - offset: i64, - mut reply: ReplyDirectory, - ) { + &self, + ctx: &Context, + inode: Self::Inode, + handle: Self::Handle, + size: u32, + offset: u64, + add_entry: &mut dyn FnMut(DirEntry) -> std::io::Result, + ) -> std::io::Result<()> { if offset == 0 { - reply.add(ino, 1, FileType::Directory, "."); - reply.add(ino, 2, FileType::Directory, ".."); + add_entry(DirEntry { + name: b".\0", + ino: inode, + offset: 1, + type_: libc::S_IFDIR as u32, + })?; - if ino == 1 { - // Root - show Home folder - reply.add(2, 3, FileType::Directory, "Home"); - } else { - let node_id = self.find_node_id_by_inode(ino); - - match node_id { - Some(id) => { - let children = self.db.list_children(&id).ok(); - let mut child_offset = 3; - - for child_name in children { - reply.add( - child_offset, - child_offset + 1, - FileType::RegularFile, - &child_name, - ); - child_offset += 1; - } - } - None => {} - } - } + add_entry(DirEntry { + name: b"..\0", + ino: 1, + offset: 2, + type_: libc::S_IFDIR as u32, + })?; } - reply.ok(); + Ok(()) } -} + + fn releasedir( + &self, + ctx: &Context, + inode: Self::Inode, + flags: u32, + handle: Self::Handle, + ) -> std::io::Result<()> { + Ok(()) + } + + fn statfs( + &self, + ctx: &Context, + inode: Self::Inode, + ) -> std::io::Result { + let mut st = unsafe { std::mem::zeroed::() }; + st.f_bsize = 4096; + st.f_blocks = 1000000; + st.f_bfree = 500000; + st.f_bavail = 500000; + st.f_files = 1000; + st.f_ffree = 500; + st.f_favail = 500; + st.f_namemax = 255; + Ok(st) + } +} \ No newline at end of file diff --git a/markbase-fuse/src/main.rs b/markbase-fuse/src/main.rs index 4d0d992..dee9d3f 100644 --- a/markbase-fuse/src/main.rs +++ b/markbase-fuse/src/main.rs @@ -2,7 +2,6 @@ use anyhow::Result; use clap::{Parser, Subcommand}; use std::path::PathBuf; use std::sync::Arc; -use std::sync::Mutex; #[derive(Parser)] #[command(name = "markbase-fuse", about = "MarkBase FUSE Mount Tool")] @@ -43,7 +42,8 @@ fn main() -> Result<()> { } fn mount_user(user: String, tree_type: String, dir: PathBuf) -> Result<()> { - use fuse::mount; + use fuse_backend_rs::api::server::Server; + use fuse_backend_rs::transport::FuseSession; use markbase_fuse::MarkBaseFs; use std::env::current_dir; @@ -61,7 +61,7 @@ fn mount_user(user: String, tree_type: String, dir: PathBuf) -> Result<()> { std::fs::create_dir_all(&dir)?; } - println!("=== MarkBase FUSE (fuse crate + FUSE-T) ==="); + println!("=== MarkBase FUSE (fuse-backend-rs + fuse-t) ==="); println!("User: {}", user); println!("Tree Type: {}", tree_type); println!("Database: {}", db_path.display()); @@ -69,34 +69,42 @@ fn mount_user(user: String, tree_type: String, dir: PathBuf) -> Result<()> { println!(""); let fs = MarkBaseFs::new(&db_path.to_string_lossy(), &tree_type)?; - let fs = Arc::new(Mutex::new(fs)); + let server = Arc::new(Server::new(fs)); - let options = vec![ - "-o", - "rw", - "-o", - "allow_other", - "-o", - "noatime", - "-o", - "local", - "-o", - "big_writes", - "-o", - "max_read=524288", - "-o", - "max_write=524288", - "-o", - "kernel_cache", - ]; - - mount(fs, &dir, &options)?; + let mut session = FuseSession::new(&dir, "markbase", "markbase-fuse", false)?; + session.mount()?; println!("Mounted successfully!"); println!("Press Ctrl+C to unmount..."); + let mut channel = session.new_channel()?; + + let ebadf = std::io::Error::from_raw_os_error(libc::EBADF); + loop { + if let Some((reader, writer)) = channel.get_request()? { + if let Err(e) = server.handle_message(reader, writer.into(), None, None) { + match e { + fuse_backend_rs::Error::EncodeMessage(e) if e.kind() == std::io::ErrorKind::Other => { + break; + } + _ => { + eprintln!("Handling fuse message failed: {:?}", e); + continue; + } + } + } + } else { + println!("fuse server exits"); + break; + } + } + + session.umount()?; + println!("Unmounted successfully"); + Ok(()) } + fn unmount_user(dir: PathBuf) -> Result<()> { println!("Unmounting: {}", dir.display()); @@ -104,4 +112,4 @@ fn unmount_user(dir: PathBuf) -> Result<()> { println!("Unmounted successfully"); Ok(()) -} +} \ No newline at end of file