diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 89f714a..d372b24 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,6 +18,7 @@ jobs: rust: [stable, beta] steps: - uses: actions/checkout@v4 + - name: Install Rust ${{ matrix.rust }} uses: dtolnay/rust-toolchain@master diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 97bd40f..f580d7f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - name: Install Rust uses: dtolnay/rust-toolchain@stable @@ -30,6 +31,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - name: Install Rust uses: dtolnay/rust-toolchain@stable @@ -62,6 +64,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - name: Install Rust uses: dtolnay/rust-toolchain@stable @@ -95,6 +98,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - name: Install Rust uses: dtolnay/rust-toolchain@stable diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index 2fc980b..c72556b 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -15,6 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - name: Install Rust uses: dtolnay/rust-toolchain@stable diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index da7ed50..0acb6f5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,6 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - name: Install Rust uses: dtolnay/rust-toolchain@stable diff --git a/Cargo.lock b/Cargo.lock index da95048..e742020 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -126,9 +126,9 @@ checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "arrayvec" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +checksum = "f02882884d3e1bc524fb12c79f107f6ad0e1cfd498c536ffb494301740995dfe" [[package]] name = "assert_cmd" @@ -430,9 +430,9 @@ dependencies = [ [[package]] name = "bitvec" -version = "1.0.1" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +checksum = "ddcec3d12c579d40898fe0a9a358a803c23e9c52ca3c425707f81c9436211837" dependencies = [ "funty", "radium", @@ -528,19 +528,20 @@ dependencies = [ [[package]] name = "borsh" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" +checksum = "2f3f6da4992df95bbcd9af42a6c7dcb994498fc9048230405f3b36ff7cd3f145" dependencies = [ "borsh-derive", + "bytes", "cfg_aliases", ] [[package]] name = "borsh-derive" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" +checksum = "3ae8fb4fb5740e4b2c4884ff95f5f32f5e8479db1e8fd8eb49ddbe09eb09bb7c" dependencies = [ "once_cell", "proc-macro-crate", @@ -799,9 +800,9 @@ dependencies = [ [[package]] name = "crc-catalog" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" +checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" [[package]] name = "crc32fast" @@ -2081,9 +2082,9 @@ checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] name = "libfuse-fs" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61be2a0235d6a5ba30064c172f12d5465da0f013281a0e6675604d0781496e9" +checksum = "818b22fed635a8c39500037246a136595ac01fdc00c029dce59b42f6bd800f39" dependencies = [ "async-trait", "bitflags 2.11.0", @@ -2150,9 +2151,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.24" +version = "1.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4735e9cbde5aac84a5ce588f6b23a90b9b0b528f6c5a8db8a4aff300463a0839" +checksum = "85bc9657773828b90eeb625adff10eeac83cc21bbfd8e23a03eaa8a33c9e28d9" dependencies = [ "cc", "pkg-config", @@ -2216,6 +2217,17 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +[[package]] +name = "mac_address" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0aeb26bf5e836cc1c341c8106051b573f1766dfa05aa87f0b98be5e51b02303" +dependencies = [ + "nix", + "serde", + "winapi", +] + [[package]] name = "matchers" version = "0.2.0" @@ -2417,7 +2429,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand 0.8.5", + "rand 0.8.6", "smallvec", "zeroize", ] @@ -2691,9 +2703,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pgvector" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc58e2d255979a31caa7cabfa7aac654af0354220719ab7a68520ae7a91e8c0b" +checksum = "3673cba5b9a124916096a423b806a9f29620972c6c97b08db5f2053e9428b481" dependencies = [ "serde", ] @@ -2835,9 +2847,9 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ "toml_edit", ] @@ -3037,9 +3049,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -3096,9 +3108,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" dependencies = [ "either", "rayon-core", @@ -3290,9 +3302,9 @@ dependencies = [ [[package]] name = "rfuse3" -version = "0.0.8" +version = "0.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5d7bea55817b58bd3a706ac0671f9aedc06d2d91e2f68272bd4fbe62f817d2b" +checksum = "f6edadac8a81eefae9a2c3ad55cb5af4b8421cb27e44bc8a3334916973582bd2" dependencies = [ "aligned_box", "async-notify", @@ -3377,18 +3389,19 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.40.0" +version = "1.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61f703d19852dbf87cbc513643fa81428361eb6940f1ac14fd58155d295a3eb0" +checksum = "be2a24f50780bc85f09cc6ac299bdf1424302742d77221106859c9d8b102126a" dependencies = [ "arrayvec", "borsh", "bytes", "num-traits", - "rand 0.8.5", + "rand 0.8.6", "rkyv", "serde", "serde_json", + "wasm-bindgen", ] [[package]] @@ -3589,7 +3602,7 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "scorpiofs" -version = "0.2.2" +version = "0.2.3" dependencies = [ "assert_cmd", "async-recursion", @@ -3652,9 +3665,9 @@ dependencies = [ [[package]] name = "sea-orm" -version = "1.1.19" +version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d945f62558fac19e5988680d2fdf747b734c2dbc6ce2cb81ba33ed8dde5b103" +checksum = "2dc312fedd460a47ea563911761d254a84e7b51d8cc73ec92c929e78f33fa957" dependencies = [ "async-stream", "async-trait", @@ -3663,6 +3676,7 @@ dependencies = [ "derive_more", "futures-util", "log", + "mac_address", "ouroboros", "pgvector", "rust_decimal", @@ -3682,9 +3696,9 @@ dependencies = [ [[package]] name = "sea-orm-macros" -version = "1.1.19" +version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c2e64a50a9cc8339f10a27577e10062c7f995488e469f2c95762c5ee847832" +checksum = "9b9a3f90e336ec74803e8eb98c61bc98754c1adfba3b4f84d946237b752b1c88" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -3963,9 +3977,9 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" [[package]] name = "simdutf8" @@ -4157,7 +4171,7 @@ dependencies = [ "memchr", "once_cell", "percent-encoding", - "rand 0.8.5", + "rand 0.8.6", "rsa", "rust_decimal", "serde", @@ -4201,7 +4215,7 @@ dependencies = [ "memchr", "num-bigint", "once_cell", - "rand 0.8.5", + "rand 0.8.6", "rust_decimal", "serde", "serde_json", @@ -4627,7 +4641,7 @@ dependencies = [ "indexmap 2.13.0", "serde_core", "serde_spanned", - "toml_datetime", + "toml_datetime 0.7.5+spec-1.1.0", "toml_parser", "toml_writer", "winnow", @@ -4642,14 +4656,23 @@ dependencies = [ "serde_core", ] +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" -version = "0.23.10+spec-1.0.0" +version = "0.25.4+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +checksum = "7193cbd0ce53dc966037f54351dbbcf0d5a642c7f0038c382ef9e677ce8c13f2" dependencies = [ "indexmap 2.13.0", - "toml_datetime", + "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", "winnow", ] @@ -4852,9 +4875,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" -version = "1.19.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "unicode-bidi" @@ -5084,6 +5107,7 @@ dependencies = [ "cfg-if", "once_cell", "rustversion", + "serde", "wasm-bindgen-macro", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index bd42da3..e61a9a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "scorpiofs" -version = "0.2.2" +version = "0.2.3" edition = "2021" description = "FUSE-based virtual filesystem with Antares overlay for monorepo builds" license = "MIT OR Apache-2.0" @@ -22,7 +22,11 @@ reqwest = { version = "0.13.1", features = ["json", "blocking"] } serde = { version = "1.0.228", features = ["derive"] } tokio = { version = "1.49.0", features = ["full"] } axum = { version = "0.8.8", features = ["macros"] } -rfuse3 = { version = "0.0.8", features = ["tokio-runtime", "unprivileged", "file-lock"] } +rfuse3 = { version = "0.0.9", features = [ + "tokio-runtime", + "unprivileged", + "file-lock", +] } clap = { version = "4.5.57", features = ["derive"] } toml = "0.9.8" @@ -39,7 +43,7 @@ async-recursion = "1.1.1" bytes = "1.11.1" futures = "0.3.31" uuid = { version = "1.20.0", features = ["v4"] } -libfuse-fs = { version = "0.1.13"} +libfuse-fs = "0.1.14" whoami = "1.6.0" thiserror = "2.0.18" crossbeam = "0.8.4" diff --git a/src/antares/fuse.rs b/src/antares/fuse.rs index 2d04d66..7eabbad 100644 --- a/src/antares/fuse.rs +++ b/src/antares/fuse.rs @@ -1,7 +1,7 @@ use std::{path::PathBuf, sync::Arc}; use libfuse_fs::{ - passthrough::{new_passthroughfs_layer, PassthroughArgs}, + passthrough::new_antares_passthroughfs_layer, unionfs::{config::Config, layer::Layer, OverlayFs}, }; use tokio::task::JoinHandle; @@ -49,24 +49,15 @@ impl AntaresFuse { let mut lower_layers: Vec> = Vec::new(); if let Some(cl_dir) = &self.cl_dir { - let cl_layer = new_passthroughfs_layer(PassthroughArgs { - root_dir: cl_dir, - mapping: None::, - }) - .await?; + let cl_layer = new_antares_passthroughfs_layer(cl_dir).await?; lower_layers.push(Arc::new(cl_layer) as Arc); } lower_layers.push(self.dic.clone() as Arc); // Upper layer mirrors upper_dir to keep writes separated from lower layers. - let upper_layer: Arc = Arc::new( - new_passthroughfs_layer(PassthroughArgs { - root_dir: &self.upper_dir, - mapping: None::, - }) - .await?, - ); + let upper_layer: Arc = + Arc::new(new_antares_passthroughfs_layer(&self.upper_dir).await?); // passthrough Upper - readwrite file system over upper dir // passthrough CL - readwrite file system over upper dir diff --git a/tests/antares_test.rs b/tests/antares_test.rs index daaef11..e911e9b 100644 --- a/tests/antares_test.rs +++ b/tests/antares_test.rs @@ -43,6 +43,9 @@ fn init_config() { #[tokio::test] async fn test_mount_and_list_registers_instance() { init_config(); + if !fuse_prereqs_available() { + return; + } let root = tempdir().unwrap(); let paths = AntaresPaths::new( @@ -75,6 +78,9 @@ async fn test_mount_and_list_registers_instance() { #[tokio::test] async fn test_mount_job_at_custom_path() { init_config(); + if !fuse_prereqs_available() { + return; + } let root = tempdir().unwrap(); let custom_mount = root.path().join("custom_mountpoint"); @@ -117,6 +123,9 @@ async fn test_mount_job_at_custom_path() { #[tokio::test] async fn test_mount_job_at_multiple_custom_paths() { init_config(); + if !fuse_prereqs_available() { + return; + } let root = tempdir().unwrap(); let paths = AntaresPaths::new( @@ -161,6 +170,9 @@ async fn test_mount_job_at_multiple_custom_paths() { #[tokio::test] async fn test_mount_job_at_with_pathbuf() { init_config(); + if !fuse_prereqs_available() { + return; + } let root = tempdir().unwrap(); let paths = AntaresPaths::new( @@ -421,6 +433,67 @@ async fn test_fuse_multiple_custom_mounts() { } } +/// Run with: +/// sudo -E cargo test --test antares_test test_fuse_write_then_metadata -- --exact --ignored --nocapture +#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +#[ignore] +#[serial] +async fn test_fuse_write_then_metadata() { + let test_future = async { + init_config(); + + if !fuse_prereqs_available() { + return; + } + + let test_id = Uuid::new_v4(); + let base = PathBuf::from(format!("/tmp/antares_write_meta_test_{test_id}")); + let _ = std::fs::remove_dir_all(&base); + + let mountpoint = base.join("workspace"); + let paths = AntaresPaths::new( + base.join("upper"), + base.join("cl"), + base.join("mnt"), + base.join("state.toml"), + ); + let manager = AntaresManager::new(paths).await; + + let config = manager + .mount_job_at("write-meta-test-job", mountpoint.clone(), None) + .await + .expect("mount_job_at should succeed"); + sleep(Duration::from_millis(500)).await; + + // Buck2 pattern: write linker_wrapper.sh, then immediate metadata + chmod. + let out_dir = config + .mountpoint + .join("buck-out/v2/gen/linker_wrapper/a83718dde72c05c6"); + std::fs::create_dir_all(&out_dir).expect("mkdir buck-out path should succeed"); + + let script = out_dir.join("linker_wrapper.sh"); + std::fs::write(&script, b"#!/bin/sh\nexec \"$@\"\n").expect("write should succeed"); + + let meta = std::fs::metadata(&script).expect("metadata after write should succeed"); + assert!(meta.is_file()); + + use std::os::unix::fs::PermissionsExt; + std::fs::set_permissions(&script, std::fs::Permissions::from_mode(0o755)) + .expect("set_permissions after write should succeed"); + + manager + .umount_job("write-meta-test-job") + .await + .expect("manager umount should succeed"); + let _ = std::fs::remove_dir_all(&base); + }; + + match tokio::time::timeout(Duration::from_secs(120), test_future).await { + Ok(_) => println!("✓ Test passed"), + Err(_) => panic!("Test timed out"), + } +} + /// Test that appending to an existing file on an Antares FUSE mount succeeds. /// /// This covers the reproduced regression where reopening an existing file with