diff --git a/Cargo.lock b/Cargo.lock index c4d7e82eedb4..0381b429dd07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,9 +79,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.4" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" dependencies = [ "anstyle", "anstyle-parse", @@ -1372,9 +1372,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.8" +version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" +checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" dependencies = [ "clap_builder", "clap_derive", @@ -1382,9 +1382,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.8" +version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" +checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" dependencies = [ "anstream", "anstyle", @@ -1706,7 +1706,7 @@ dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset", + "memoffset 0.9.0", "scopeguard", ] @@ -2665,11 +2665,12 @@ dependencies = [ "futures-channel", "futures-util", "libc", - "nix", + "nix 0.26.4", "serde", "slab", "tokio", "tracing", + "which", ] [[package]] @@ -3928,6 +3929,15 @@ dependencies = [ "libc", ] +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + [[package]] name = "memoffset" version = "0.9.0" @@ -4379,6 +4389,18 @@ dependencies = [ "bitflags 1.3.2", "cfg-if", "libc", + "memoffset 0.7.1", +] + +[[package]] +name = "nix" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "libc", ] [[package]] @@ -4572,12 +4594,18 @@ dependencies = [ name = "ofs" version = "0.0.1" dependencies = [ + "anyhow", "async-trait", + "clap", + "env_logger", "fuse3", "futures-util", "libc", "log", + "nix 0.27.1", "opendal", + "tokio", + "url", ] [[package]] @@ -5652,7 +5680,7 @@ dependencies = [ "cfg-if", "indoc", "libc", - "memoffset", + "memoffset 0.9.0", "parking_lot 0.12.1", "pyo3-build-config", "pyo3-ffi", diff --git a/bin/ofs/Cargo.toml b/bin/ofs/Cargo.toml index 1829f0788204..860904d7cead 100644 --- a/bin/ofs/Cargo.toml +++ b/bin/ofs/Cargo.toml @@ -31,8 +31,19 @@ rust-version.workspace = true [dependencies] async-trait = "0.1.75" -fuse3 = { "version" = "0.6.1", "features" = ["tokio-runtime"] } +fuse3 = { "version" = "0.6.1", "features" = ["tokio-runtime", "unprivileged"] } futures-util = "0.3.30" libc = "0.2.151" log = "0.4.20" +anyhow = "1" +tokio = { version = "1.34", features = [ + "fs", + "macros", + "rt-multi-thread", + "io-std", +] } +nix = { version = "0.27.1", features = ["user"] } +env_logger = "0.10" +clap = { version = "4.4.18", features = ["derive", "env"] } +url = "2.5.0" opendal.workspace = true diff --git a/bin/ofs/src/bin/ofs.rs b/bin/ofs/src/bin/ofs.rs new file mode 100644 index 000000000000..08399b56ef22 --- /dev/null +++ b/bin/ofs/src/bin/ofs.rs @@ -0,0 +1,83 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::collections::HashMap; +use std::str::FromStr; + +use anyhow::anyhow; +use anyhow::Context; +use anyhow::Result; +use clap::Parser; +use fuse3::path::Session; +use fuse3::MountOptions; +use ofs::Ofs; +use opendal::Operator; +use opendal::Scheme; +use url::Url; + +#[tokio::main] +async fn main() -> Result<()> { + env_logger::init(); + fuse().await +} + +#[derive(Parser, Debug)] +#[command(version, about)] +struct Config { + /// fuse mount path + #[arg(env = "OFS_MOUNT_PATH", index = 1)] + mount_path: String, + + /// location of opendal service + /// format: ://?=&= + /// example: fs://root=/tmp + #[arg(env = "OFS_BACKEND", index = 2)] + backend: String, +} + +async fn fuse() -> Result<()> { + let cfg = Config::try_parse().context("parse command line arguments")?; + + let location = Url::parse(&cfg.backend)?; + if location.has_host() { + Err(anyhow!("Host part in a location is not supported."))?; + } + + let scheme_str = location.scheme(); + + let op_args = location + .query_pairs() + .into_owned() + .collect::>(); + + let scheme = Scheme::from_str(scheme_str).context("unsupported scheme")?; + let op = Operator::via_map(scheme, op_args)?; + + let mut mount_option = MountOptions::default(); + mount_option.uid(nix::unistd::getuid().into()); + mount_option.gid(nix::unistd::getgid().into()); + + let ofs = Ofs { op }; + + let mounthandle = Session::new(mount_option) + .mount_with_unprivileged(ofs, cfg.mount_path) + .await?; + + mounthandle.await?; + + Ok(()) +}