fuse-overlayfs
This commit is contained in:
parent
002a981071
commit
cd0a1527f2
11 changed files with 1395 additions and 111 deletions
828
Cargo.lock
generated
828
Cargo.lock
generated
|
@ -2,6 +2,101 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.68.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"log",
|
||||
"peeking_take_while",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
"syn",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "char_enum"
|
||||
version = "0.1.0"
|
||||
|
@ -18,6 +113,36 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.13.0"
|
||||
|
@ -44,6 +169,143 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
|
||||
|
||||
[[package]]
|
||||
name = "home"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"windows-core 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.14.0"
|
||||
|
@ -53,6 +315,127 @@ dependencies = [
|
|||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.170"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "peeking_take_while"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.93"
|
||||
|
@ -71,6 +454,101 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[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.38.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.218"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.218"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.98"
|
||||
|
@ -82,6 +560,46 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc"
|
||||
dependencies = [
|
||||
"thiserror-impl 2.0.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.17"
|
||||
|
@ -95,4 +613,314 @@ dependencies = [
|
|||
"char_enum",
|
||||
"enumflags2",
|
||||
"itertools",
|
||||
"winfsp",
|
||||
"wmi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
|
||||
dependencies = [
|
||||
"either",
|
||||
"home",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "widestring"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
|
||||
dependencies = [
|
||||
"windows-core 0.52.0",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.60.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddf874e74c7a99773e62b1c671427abf01a425e77c3d3fb9fb1e4883ea934529"
|
||||
dependencies = [
|
||||
"windows-collections",
|
||||
"windows-core 0.60.1",
|
||||
"windows-future",
|
||||
"windows-link",
|
||||
"windows-numerics",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-collections"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5467f79cc1ba3f52ebb2ed41dbb459b8e7db636cc3429458d9a852e15bc24dec"
|
||||
dependencies = [
|
||||
"windows-core 0.60.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.60.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca21a92a9cae9bf4ccae5cf8368dce0837100ddf6e6d57936749e85f152f6247"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-future"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a787db4595e7eb80239b74ce8babfb1363d8e343ab072f2ffe901400c03349f0"
|
||||
dependencies = [
|
||||
"windows-core 0.60.1",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb26fd936d991781ea39e87c3a27285081e3c0da5ca0fcbc02d368cc6f52ff01"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3"
|
||||
|
||||
[[package]]
|
||||
name = "windows-numerics"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "005dea54e2f6499f2cee279b8f703b3cf3b5734a2d8d21867c8f44003182eeed"
|
||||
dependencies = [
|
||||
"windows-core 0.60.1",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06374efe858fab7e4f881500e6e86ec8bc28f9462c47e5a9941a0142ad86b189"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winfsp"
|
||||
version = "0.11.3+winfsp-2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "583f578b24fce35aedd77408b096d78740bd9bddf213f7859dc3571b2f3ff828"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"paste",
|
||||
"static_assertions",
|
||||
"thiserror 1.0.69",
|
||||
"widestring",
|
||||
"windows 0.52.0",
|
||||
"winfsp-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winfsp-sys"
|
||||
version = "0.2.2+winfsp-2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbabd94628121ac484d3ab764430e1ded8d5fdf5f940e1f0d08971c394dbd59f"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wmi"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae33d16f05f9b4b819abe7a9472bad4acb17f5b5d52d3f422762ebec613c65a6"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"futures",
|
||||
"log",
|
||||
"serde",
|
||||
"thiserror 2.0.11",
|
||||
"windows 0.60.0",
|
||||
"windows-core 0.60.1",
|
||||
]
|
||||
|
|
|
@ -7,3 +7,7 @@ edition = "2021"
|
|||
char_enum = { version = "0.1.0", path = "crates/char_enum", features = ["derive"] }
|
||||
enumflags2 = "0.7.11"
|
||||
itertools = "0.14.0"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winfsp = "0.11.3"
|
||||
wmi = "0.15.1"
|
||||
|
|
|
@ -4,38 +4,22 @@ pub use char_enum_derive;
|
|||
use std::{error::Error, fmt::Display};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct FromCharError {
|
||||
message: String,
|
||||
}
|
||||
|
||||
impl FromCharError {
|
||||
pub fn new(message: String) -> Self {
|
||||
Self { message }
|
||||
}
|
||||
}
|
||||
pub struct FromCharError(pub char);
|
||||
|
||||
impl Display for FromCharError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.message)
|
||||
write!(f, "invalid char: {}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for FromCharError {}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct FromStrError {
|
||||
message: String,
|
||||
}
|
||||
|
||||
impl FromStrError {
|
||||
pub fn new(message: String) -> Self {
|
||||
Self { message }
|
||||
}
|
||||
}
|
||||
pub struct FromStrError(pub String);
|
||||
|
||||
impl Display for FromStrError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.message)
|
||||
write!(f, "invalid string: {}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,7 +27,7 @@ impl Error for FromStrError {}
|
|||
|
||||
impl From<FromCharError> for FromStrError {
|
||||
fn from(value: FromCharError) -> Self {
|
||||
Self::new(value.to_string())
|
||||
Self(value.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -135,7 +135,7 @@ impl From<TypedIdRange> for UntypedIdRange {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ParseIdRangeError(String);
|
||||
|
||||
impl Display for ParseIdRangeError {
|
||||
|
|
|
@ -70,34 +70,52 @@ impl Display for KeyValuePair {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct MountOptions(Vec<MountOption>);
|
||||
#[derive(Debug)]
|
||||
pub struct MountOptions<T>(pub Vec<T>);
|
||||
|
||||
impl Deref for MountOptions {
|
||||
type Target = Vec<MountOption>;
|
||||
impl<T: Clone> Clone for MountOptions<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for MountOptions<T> {
|
||||
fn default() -> Self {
|
||||
Self(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for MountOptions<T> {
|
||||
type Target = Vec<T>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for MountOptions {
|
||||
impl<T> DerefMut for MountOptions<T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for MountOptions {
|
||||
type Err = ParseMountOptionError;
|
||||
impl<T> FromIterator<T> for MountOptions<T> {
|
||||
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
|
||||
Self(iter.into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromStr> FromStr for MountOptions<T> {
|
||||
type Err = T::Err;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
s.split(',')
|
||||
.map(MountOption::from_str)
|
||||
.map(T::from_str)
|
||||
.process_results(|it| MountOptions(it.collect()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for MountOptions {
|
||||
impl<T: Display> Display for MountOptions<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let options = self.0.iter().map(|x| x.to_string()).join(" ");
|
||||
write!(f, "{options}")
|
||||
|
@ -850,18 +868,18 @@ impl Display for MountOperation {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Mount {
|
||||
source: DeviceId,
|
||||
target: PathBuf,
|
||||
options: MountOptions,
|
||||
options: MountOptions<MountOption>,
|
||||
}
|
||||
|
||||
impl Mount {
|
||||
pub fn new(
|
||||
src: impl Into<DeviceId>,
|
||||
target: impl Into<PathBuf>,
|
||||
options: impl Into<MountOptions>,
|
||||
options: impl Into<MountOptions<MountOption>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
source: src.into(),
|
||||
|
@ -870,7 +888,7 @@ impl Mount {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn exec(&self) -> std::io::Result<std::process::Output> {
|
||||
pub fn mount(&self) -> std::io::Result<std::process::Output> {
|
||||
Command::new("mount")
|
||||
.arg(self.options.to_string())
|
||||
.arg(self.source.to_string())
|
||||
|
@ -901,7 +919,7 @@ mod tests {
|
|||
use crate::fs::{
|
||||
id_mapping::UntypedIdRange,
|
||||
mount::{ParseDeviceIdTypeError, ParseOptionsSourceError},
|
||||
permission::{OctalPermissions, Permissions},
|
||||
permission::Permissions,
|
||||
};
|
||||
|
||||
use super::{
|
||||
|
@ -1248,7 +1266,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
fn mount() {
|
||||
let mut options = MountOptions::default();
|
||||
options.push(MountOption::FsType(vec!["overlay"].into()));
|
||||
options.push(MountOption::MakeDir(Some(Permissions::Octal(
|
||||
|
|
|
@ -466,6 +466,19 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn modes() {
|
||||
let sym_modes = Modes::<SymbolicMode>::from_str("rwx").unwrap();
|
||||
let ids = Modes::<GroupId>::from_str("ugo").unwrap();
|
||||
|
||||
assert_eq!(
|
||||
sym_modes.0,
|
||||
SymbolicMode::Read | SymbolicMode::Write | SymbolicMode::Execute
|
||||
);
|
||||
|
||||
assert_eq!(ids.0, GroupId::User | GroupId::Group | GroupId::Other);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn symbolic_permissions() {
|
||||
let sym = Permissions::from_str("ug+w").unwrap();
|
||||
|
|
|
@ -1,65 +1,471 @@
|
|||
use std::fmt::Display;
|
||||
use std::{
|
||||
convert::Infallible,
|
||||
error::Error,
|
||||
fmt::Display,
|
||||
num::ParseIntError,
|
||||
ops::Deref,
|
||||
path::{Path, PathBuf},
|
||||
process::Command,
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use crate::fs::{id_mapping::IdMapping, AsIter, FileSystem, Mountpoint};
|
||||
use crate::fs::{
|
||||
id_mapping::{IdMapping, ParseIdRangeError},
|
||||
mount::MountOptions,
|
||||
AsIter, FileSystem, Mountpoint,
|
||||
};
|
||||
use crate::macros::*;
|
||||
|
||||
use super::{Stack, Stackable};
|
||||
use super::Stack;
|
||||
|
||||
macro_rules! impl_wrapper {
|
||||
($name:ident($inner:ty), $err:ty, $from_str:block) => {
|
||||
impl Deref for $name {
|
||||
type Target = $inner;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for $name {
|
||||
type Err = $err;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
$from_str
|
||||
//Ok(Self($target::from_str(s)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for $name {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Test(usize);
|
||||
|
||||
impl_wrapper!(Test(usize), ParseIntError, {
|
||||
Ok(Test(usize::from_str(s)?))
|
||||
});
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct ParseMaxIdleThreadsError(ParseIntError);
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct ParseMaxThreadsError(ParseIntError);
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct ParseSquashToIdError(ParseIntError);
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct ParseSquashToUidError(ParseSquashToIdError);
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct ParseSquashToGidError(ParseSquashToIdError);
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct ParseUidMappingError(ParseIdRangeError);
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct ParseGidMappingError(ParseIdRangeError);
|
||||
|
||||
impl_wrapper_err_for!(
|
||||
ParseMaxIdleThreadsError(ParseIntError),
|
||||
"invalid max idle threads"
|
||||
);
|
||||
|
||||
impl_wrapper_err_for!(ParseMaxThreadsError(ParseIntError), "invalid max threads");
|
||||
impl_wrapper_err_for!(ParseSquashToIdError(ParseIntError), "invalid id");
|
||||
impl_wrapper_err_for!(ParseSquashToUidError(ParseSquashToIdError), "invalid uid");
|
||||
impl_wrapper_err_for!(ParseSquashToGidError(ParseSquashToIdError), "invalid gid");
|
||||
impl_wrapper_err_for!(ParseUidMappingError(ParseIdRangeError), "invalid uid");
|
||||
impl_wrapper_err_for!(ParseGidMappingError(ParseIdRangeError), "invalid gid");
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||
pub struct LowerDirs(Vec<PathBuf>);
|
||||
|
||||
impl Deref for LowerDirs {
|
||||
type Target = Vec<PathBuf>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for LowerDirs {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
self.0
|
||||
.iter()
|
||||
.map(|v| v.to_string_lossy())
|
||||
.fold(String::new(), |a, b| a + &b)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for LowerDirs {
|
||||
type Err = Infallible;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Self(s.split(',').map(Into::into).collect()))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<&str>> for LowerDirs {
|
||||
fn from(value: Vec<&str>) -> Self {
|
||||
Self(value.into_iter().map(PathBuf::from).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<String>> for LowerDirs {
|
||||
fn from(value: Vec<String>) -> Self {
|
||||
Self(value.into_iter().map(PathBuf::from).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<&Path>> for LowerDirs {
|
||||
fn from(value: Vec<&Path>) -> Self {
|
||||
Self(value.into_iter().map(Path::to_path_buf).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<PathBuf>> for LowerDirs {
|
||||
fn from(value: Vec<PathBuf>) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct MaxIdleThreads(Option<usize>);
|
||||
|
||||
impl Default for MaxIdleThreads {
|
||||
fn default() -> Self {
|
||||
Self(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for MaxIdleThreads {
|
||||
type Err = ParseMaxIdleThreadsError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"-1" => Ok(Self(None)),
|
||||
s => Ok(usize::from_str_radix(s, 10).map(Some).map(Self)?),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for MaxIdleThreads {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self.0 {
|
||||
Some(n) => write!(f, "{n}"),
|
||||
None => write!(f, "-1"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct MaxThreads(usize);
|
||||
|
||||
impl Default for MaxThreads {
|
||||
fn default() -> Self {
|
||||
Self(10)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for MaxThreads {
|
||||
type Err = ParseMaxThreadsError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(usize::from_str_radix(s, 10).map(Self)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for MaxThreads {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct SquashToId(usize);
|
||||
|
||||
impl FromStr for SquashToId {
|
||||
type Err = ParseSquashToIdError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(usize::from_str_radix(s, 10).map(Self)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for SquashToId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct SquashToUid(SquashToId);
|
||||
|
||||
impl Deref for SquashToUid {
|
||||
type Target = SquashToId;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for SquashToUid {
|
||||
type Err = ParseSquashToUidError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Self(SquashToId::from_str(s)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for SquashToUid {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct SquashToGid(SquashToId);
|
||||
|
||||
impl Deref for SquashToGid {
|
||||
type Target = SquashToId;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for SquashToGid {
|
||||
type Err = ParseSquashToGidError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Self(SquashToId::from_str(s)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for SquashToGid {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct GidMapping(IdMapping);
|
||||
|
||||
impl Deref for GidMapping {
|
||||
type Target = IdMapping;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for GidMapping {
|
||||
type Err = ParseGidMappingError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Self(IdMapping::from_str(s)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for GidMapping {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct GidMapping(IdMapping);
|
||||
|
||||
impl Deref for GidMapping {
|
||||
type Target = IdMapping;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for GidMapping {
|
||||
type Err = ParseGidMappingError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Self(IdMapping::from_str(s)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for GidMapping {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum ParseFuseOverlayOptionError {
|
||||
MaxIdleThreads(ParseMaxIdleThreadsError),
|
||||
MaxThreads(ParseMaxThreadsError),
|
||||
SquashToUid(ParseSquashToUidError),
|
||||
SquashToGid(ParseSquashToGidError),
|
||||
UidMapping(ParseUidMappingError),
|
||||
GidMapping(ParseGidMappingError),
|
||||
}
|
||||
|
||||
impl Display for ParseFuseOverlayOptionError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::MaxIdleThreads(e) => write!(f, "{e}"),
|
||||
Self::MaxThreads(e) => write!(f, "{e}"),
|
||||
Self::SquashToUid(e) => write!(f, "{e}"),
|
||||
Self::SquashToGid(e) => write!(f, "{e}"),
|
||||
Self::UidMapping(e) => write!(f, "{e}"),
|
||||
Self::GidMapping(e) => write!(f, "{e}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for ParseFuseOverlayOptionError {}
|
||||
|
||||
impl_from_variants!(
|
||||
ParseFuseOverlayOptionError,
|
||||
MaxIdleThreads(ParseMaxIdleThreadsError),
|
||||
MaxThreads(ParseMaxThreadsError)
|
||||
);
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum FuseOverlayOption {
|
||||
LowerDir(LowerDirs),
|
||||
UpperDir(PathBuf),
|
||||
WorkDir(PathBuf),
|
||||
CloneFd,
|
||||
MaxIdleThreads(isize),
|
||||
MaxThreads(usize),
|
||||
MaxIdleThreads(MaxIdleThreads),
|
||||
MaxThreads(MaxThreads),
|
||||
AllowOther,
|
||||
AllowRoot,
|
||||
SquashToRoot,
|
||||
SquashToUid(usize),
|
||||
SquashToGid(usize),
|
||||
SquashToUid(SquashToUid),
|
||||
SquashToGid(SquashToGid),
|
||||
StaticNLink,
|
||||
NoAcl,
|
||||
UidMapping(IdMapping),
|
||||
GidMapping(IdMapping),
|
||||
}
|
||||
|
||||
impl_from_variants!(
|
||||
FuseOverlayOption,
|
||||
LowerDir(LowerDirs),
|
||||
MaxIdleThreads(MaxIdleThreads),
|
||||
MaxThreads(MaxThreads),
|
||||
SquashToUid(SquashToUid),
|
||||
SquashToGid(SquashToGid)
|
||||
);
|
||||
|
||||
impl FromStr for FuseOverlayOption {
|
||||
type Err = ParseFuseOverlayOptionError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let s = s.trim().trim_start_matches('-');
|
||||
|
||||
let option = match s.split_once(|delim| delim == ' ' || delim == '=') {
|
||||
Some((option, value)) => (option, Some(value)),
|
||||
None => (s, None),
|
||||
};
|
||||
|
||||
match option {
|
||||
("lowerdir", Some(args)) => Ok(LowerDirs::from_str(args).unwrap().into()),
|
||||
("upperdir", Some(args)) => Ok(Self::UpperDir(PathBuf::from(args))),
|
||||
("workdir", Some(args)) => Ok(Self::WorkDir(PathBuf::from(args))),
|
||||
("clonefd", None) => Ok(Self::CloneFd),
|
||||
("max_idle_threads", Some(args)) => Ok(MaxIdleThreads::from_str(args).into()?),
|
||||
("max_threads", Some(args)) => Ok(MaxThreads::from_str(args).into()?),
|
||||
("allow_other", None) => Ok(Self::AllowOther),
|
||||
("allow_root", None) => Ok(Self::AllowRoot),
|
||||
("squash_to_root", None) => Ok(Self::SquashToRoot),
|
||||
("squash_to_uid", Some(uid)) => Ok(SquashToUid::from_str(uid).into()?),
|
||||
("squash_to_gid", Some(gid)) => Ok(SquashToGid::from_str(gid).into()?),
|
||||
("static_nlink", None) => Ok(Self::StaticNLink),
|
||||
("noacl", None) => Ok(Self::NoAcl),
|
||||
("uidmapping", Some(ids)) => Ok(Self::UidMapping(IdMapping::from_str(ids)?)),
|
||||
("gidmapping", Some(ids)) => Ok(Self::GidMapping(IdMapping::from_str(ids)?)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for FuseOverlayOption {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
write!(f, "-o ")?;
|
||||
|
||||
match self {
|
||||
FuseOverlayOption::CloneFd => "clone_fd".to_string(),
|
||||
FuseOverlayOption::MaxIdleThreads(n) => format!("max_idle_threads={n}"),
|
||||
FuseOverlayOption::MaxThreads(n) => format!("max_threads={n}"),
|
||||
FuseOverlayOption::AllowOther => "allow_other".to_string(),
|
||||
FuseOverlayOption::AllowRoot => "allow_root".to_string(),
|
||||
FuseOverlayOption::SquashToRoot => "squash_to_root".to_string(),
|
||||
FuseOverlayOption::SquashToUid(uid) => format!("squash_to_uid={uid}"),
|
||||
FuseOverlayOption::SquashToGid(gid) => format!("squash_to_gid={gid}"),
|
||||
FuseOverlayOption::StaticNLink => "static_nlink".to_string(),
|
||||
FuseOverlayOption::NoAcl => "noacl".to_string(),
|
||||
FuseOverlayOption::UidMapping(map) => format!("uidmapping={map}"),
|
||||
FuseOverlayOption::GidMapping(map) => format!("gidmapping={map}"),
|
||||
FuseOverlayOption::LowerDir(lower) => write!(f, "{lower}"),
|
||||
FuseOverlayOption::UpperDir(path) => write!(f, "{}", path.to_string_lossy()),
|
||||
FuseOverlayOption::WorkDir(path) => write!(f, "{}", path.to_string_lossy()),
|
||||
FuseOverlayOption::CloneFd => write!(f, "clone_fd"),
|
||||
FuseOverlayOption::MaxIdleThreads(n) => write!(f, "max_idle_threads={n}"),
|
||||
FuseOverlayOption::MaxThreads(n) => write!(f, "max_threads={n}"),
|
||||
FuseOverlayOption::AllowOther => write!(f, "allow_other"),
|
||||
FuseOverlayOption::AllowRoot => write!(f, "allow_root"),
|
||||
FuseOverlayOption::SquashToRoot => write!(f, "squash_to_root"),
|
||||
FuseOverlayOption::SquashToUid(uid) => write!(f, "squash_to_uid={uid}"),
|
||||
FuseOverlayOption::SquashToGid(gid) => write!(f, "squash_to_gid={gid}"),
|
||||
FuseOverlayOption::StaticNLink => write!(f, "static_nlink"),
|
||||
FuseOverlayOption::NoAcl => write!(f, "noacl"),
|
||||
FuseOverlayOption::UidMapping(map) => write!(f, "uidmapping={map}"),
|
||||
FuseOverlayOption::GidMapping(map) => write!(f, "gidmapping={map}"),
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FuseOverlay {
|
||||
fs: Stackable,
|
||||
options: Vec<FuseOverlayOption>,
|
||||
lower_dir: usize,
|
||||
upper_dir: Option<usize>,
|
||||
work_dir: Option<usize>,
|
||||
options: MountOptions<FuseOverlayOption>,
|
||||
}
|
||||
|
||||
impl FuseOverlay {
|
||||
pub fn new(lowerdir: impl Into<LowerDirs>) -> Self {
|
||||
Self {
|
||||
lower_dir: 0,
|
||||
upper_dir: None,
|
||||
work_dir: None,
|
||||
options: MountOptions(vec![FuseOverlayOption::LowerDir(lowerdir.into())]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Stack for FuseOverlay {
|
||||
fn lower_dirs(&self) -> impl Iterator<Item = &std::path::Path> {
|
||||
self.fs.lower_dirs()
|
||||
match self.options.get(self.lower_dir) {
|
||||
Some(FuseOverlayOption::LowerDir(lower)) => lower.as_iter().map(AsRef::as_ref),
|
||||
_ => panic!("invalid lowerdir option"),
|
||||
}
|
||||
}
|
||||
|
||||
fn upper_dir(&self) -> Option<&std::path::Path> {
|
||||
self.fs.upper_dir()
|
||||
let upper = self.upper_dir.and_then(|i| self.options.get(i));
|
||||
|
||||
match upper {
|
||||
Some(FuseOverlayOption::UpperDir(upper)) => Some(upper),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn work_dir(&self) -> Option<&std::path::Path> {
|
||||
self.fs.work_dir()
|
||||
let work = self.work_dir.and_then(|i| self.options.get(i));
|
||||
|
||||
match work {
|
||||
Some(FuseOverlayOption::WorkDir(work)) => Some(work),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,10 +477,36 @@ impl Mountpoint for FuseOverlay {
|
|||
|
||||
impl FileSystem for FuseOverlay {
|
||||
fn mount(&mut self) -> std::io::Result<()> {
|
||||
todo!()
|
||||
let mut cmd = Command::new("fuse-overlayfs").arg(self.options.to_string());
|
||||
|
||||
if self.fs.lower.len() > 0 {
|
||||
cmd.arg(format!("-o lowerdir={}", self.fs.lower));
|
||||
};
|
||||
|
||||
if let Some(upper) = &self.fs.upper {
|
||||
cmd.arg(format!("-o upperdir={}", upper.to_string_lossy()));
|
||||
};
|
||||
|
||||
if let Some(work) = &self.fs.work {
|
||||
cmd.arg(format!("-o workdir={}", work.to_string_lossy()));
|
||||
};
|
||||
|
||||
cmd.output()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn unmount(&mut self) -> std::io::Result<()> {
|
||||
todo!()
|
||||
if let Some(upper) = &self.fs.upper {
|
||||
Command::new("fusermount").arg("-u").arg(upper).output()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for FuseOverlay {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "fuse-overlayfs")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,51 +1,10 @@
|
|||
pub mod fuse_overlay;
|
||||
pub mod overlay;
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::Path;
|
||||
|
||||
pub trait Stack {
|
||||
fn lower_dirs(&self) -> impl Iterator<Item = &Path>;
|
||||
fn upper_dir(&self) -> Option<&Path>;
|
||||
fn work_dir(&self) -> Option<&Path>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Stackable {
|
||||
lower: Vec<PathBuf>,
|
||||
upper: Option<PathBuf>,
|
||||
work: Option<PathBuf>,
|
||||
}
|
||||
|
||||
impl Stackable {
|
||||
pub fn new(lower: Vec<PathBuf>) -> Self {
|
||||
Self {
|
||||
lower,
|
||||
upper: None,
|
||||
work: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_upper_dir(&mut self, upper: impl Into<PathBuf>) -> &mut Self {
|
||||
self.upper = Some(upper.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_work_dir(&mut self, work: impl Into<PathBuf>) -> &mut Self {
|
||||
self.work = Some(work.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Stack for Stackable {
|
||||
fn lower_dirs(&self) -> impl Iterator<Item = &Path> {
|
||||
self.lower.iter().map(AsRef::as_ref)
|
||||
}
|
||||
|
||||
fn upper_dir(&self) -> Option<&Path> {
|
||||
self.upper.as_deref()
|
||||
}
|
||||
|
||||
fn work_dir(&self) -> Option<&Path> {
|
||||
self.work.as_deref()
|
||||
}
|
||||
}
|
||||
|
|
0
src/fs/stackable/uwf_overlay.rs
Normal file
0
src/fs/stackable/uwf_overlay.rs
Normal file
|
@ -1,4 +1,5 @@
|
|||
pub mod fs;
|
||||
mod macros;
|
||||
mod utils;
|
||||
|
||||
pub fn add(left: u64, right: u64) -> u64 {
|
||||
|
|
45
src/macros.rs
Normal file
45
src/macros.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
macro_rules! impl_from_variants {
|
||||
($enum_type:ident, $($variant:ident($inner_type:ty)),*) => {
|
||||
$(
|
||||
impl From<$inner_type> for $enum_type {
|
||||
fn from(inner: $inner_type) -> Self {
|
||||
$enum_type::$variant(inner)
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_wrapper_err_for {
|
||||
($name:ident($inner:ty), $err:literal) => {
|
||||
impl_wrapper_err!($name, $err);
|
||||
impl_from_ty!($name, $inner);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_from_ty {
|
||||
($name:ty, $from:ty) => {
|
||||
impl From<$from> for $name {
|
||||
fn from(value: $from) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_wrapper_err {
|
||||
($type:ty, $err:literal) => {
|
||||
impl Display for $type {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}: {}", self.0, $err)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for $type {}
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use impl_from_ty;
|
||||
pub(crate) use impl_from_variants;
|
||||
pub(crate) use impl_wrapper_err;
|
||||
pub(crate) use impl_wrapper_err_for;
|
Loading…
Add table
Reference in a new issue