Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package fuc for openSUSE:Factory checked in at 2026-07-14 13:49:16 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/fuc (Old) and /work/SRC/openSUSE:Factory/.fuc.new.1991 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "fuc" Tue Jul 14 13:49:16 2026 rev:11 rq:1365396 version:3.2.0 Changes: -------- --- /work/SRC/openSUSE:Factory/fuc/fuc.changes 2026-06-25 10:55:46.546414076 +0200 +++ /work/SRC/openSUSE:Factory/.fuc.new.1991/fuc.changes 2026-07-14 13:50:30.812184729 +0200 @@ -1,0 +2,9 @@ +Mon Jul 13 13:17:27 UTC 2026 - Andreas Stieger <[email protected]> + +- Update to version 3.2.0: + * Fix very poor performance on flat multi-million file + directories (now 10-20% faster than rm -rf) + * Fix a bug that caused "Directory not empty" errors on large + directories + +------------------------------------------------------------------- Old: ---- fuc-3.1.7.tar.zst New: ---- fuc-3.2.0.tar.zst ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ fuc.spec ++++++ --- /var/tmp/diff_new_pack.IHESPU/_old 2026-07-14 13:50:33.292270106 +0200 +++ /var/tmp/diff_new_pack.IHESPU/_new 2026-07-14 13:50:33.296270244 +0200 @@ -18,7 +18,7 @@ Name: fuc -Version: 3.1.7 +Version: 3.2.0 Release: 0 Summary: Modern unix commands focused on performance License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.IHESPU/_old 2026-07-14 13:50:33.344271896 +0200 +++ /var/tmp/diff_new_pack.IHESPU/_new 2026-07-14 13:50:33.352272171 +0200 @@ -3,7 +3,7 @@ <param name="url">https://github.com/SUPERCILEX/fuc.git</param> <param name="versionformat">@PARENT_TAG@</param> <param name="scm">git</param> - <param name="revision">3.1.7</param> + <param name="revision">3.2.0</param> <param name="match-tag">*</param> <param name="versionrewrite-pattern">(\d+\.\d+\.\d+)</param> <param name="versionrewrite-replacement">\1</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.IHESPU/_old 2026-07-14 13:50:33.384273273 +0200 +++ /var/tmp/diff_new_pack.IHESPU/_new 2026-07-14 13:50:33.392273548 +0200 @@ -1,7 +1,7 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/SUPERCILEX/fuc.git</param> - <param name="changesrevision">ece8652ac326fbe79e17b4381342ccf95c682684</param> + <param name="changesrevision">3aa8b04f1af491dfdb631b89a876db518bd6a363</param> </service> </servicedata> (No newline at EOF) ++++++ fuc-3.1.7.tar.zst -> fuc-3.2.0.tar.zst ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fuc-3.1.7/Cargo.lock new/fuc-3.2.0/Cargo.lock --- old/fuc-3.1.7/Cargo.lock 2026-06-22 01:20:22.000000000 +0200 +++ new/fuc-3.2.0/Cargo.lock 2026-07-13 02:21:11.000000000 +0200 @@ -87,15 +87,15 @@ [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" [[package]] name = "arrayvec" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f02882884d3e1bc524fb12c79f107f6ad0e1cfd498c536ffb494301740995dfe" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" [[package]] name = "as-slice" @@ -156,12 +156,12 @@ [[package]] name = "bstr" -version = "1.12.1" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +checksum = "5cee35f73844aa3014bb606320a6c1f010249dbdf43342fe54b5a4f6a8ed4b79" dependencies = [ "memchr", - "serde", + "serde_core", ] [[package]] @@ -172,9 +172,9 @@ [[package]] name = "bytesize" -version = "2.4.0" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49e78e506b9d7633710dab98996f22f95f3d0f488e8f1aa162830556ed9fc14d" +checksum = "3d7c8918969267b2932ffd5655509bbbea0833823058c378876953217f5fc50e" [[package]] name = "cache-size" @@ -187,9 +187,9 @@ [[package]] name = "camino" -version = "1.2.3" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ce8d3bd5823c7504d3f579f13e7b2f3da252fcb938c594d5680ee508bf846f" +checksum = "5f2d30e4173c4026932d51d31d6b0613b1fd3014bf3f9f8943d4ba139c437ba0" dependencies = [ "serde_core", ] @@ -237,9 +237,9 @@ [[package]] name = "cc" -version = "1.2.65" +version = "1.2.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96" +checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996" dependencies = [ "find-msvc-tools", "shlex 2.0.1", @@ -259,9 +259,9 @@ [[package]] name = "chacha20" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" dependencies = [ "cfg-if", "cpufeatures", @@ -375,9 +375,9 @@ [[package]] name = "console" -version = "0.16.3" +version = "0.16.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87" +checksum = "4fe5f465a4f6fee88fad41b85d990f84c835335e85b5d9e6e63e0d06d28cba7c" dependencies = [ "encode_unicode", "libc", @@ -416,16 +416,16 @@ [[package]] name = "cpz" -version = "3.1.7" +version = "3.2.0" dependencies = [ "cache-size", "clap", "criterion", - "error-stack 0.7.1", + "error-stack 0.8.0", "fuc_engine", "indicatif", "memmap2", - "rand 0.10.1", + "rand 0.10.2", "rustix", "supercilex-tests", "tempfile", @@ -475,18 +475,18 @@ [[package]] name = "crossbeam-channel" -version = "0.5.15" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +checksum = "d85363c37faeca707aef026efa9f3b34d077bce547e48f770770625c6013679e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -494,18 +494,18 @@ [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" [[package]] name = "crunchy" @@ -582,18 +582,19 @@ [[package]] name = "env_filter" -version = "1.0.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eef" +checksum = "900d271a03799a1ee8d1ca9b19893b48ca674a9284fefcfb85f05e74ed314217" dependencies = [ "log", + "regex", ] [[package]] name = "env_logger" -version = "0.11.10" +version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a" +checksum = "de671bd27a75a797dc9ae289ba1e77276e75e2026408aab65185384e2d5cd3f6" dependencies = [ "anstream", "anstyle", @@ -629,9 +630,9 @@ [[package]] name = "error-stack" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c179ac93a7a9670668c9c1558269344d224aecf2fb089bf0e215e8adf1c73643" +checksum = "d01a8d4d427153bae0c38ca68d7912cbf9903fdcc97ecac18801738b3656a46d" dependencies = [ "anyhow", "rustc_version", @@ -712,7 +713,7 @@ [[package]] name = "fuc_engine" -version = "3.1.7" +version = "3.2.0" dependencies = [ "bon", "crossbeam-channel", @@ -893,9 +894,9 @@ [[package]] name = "humantime" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" +checksum = "15cdd26707701c53297e2fa6afb323d55fbc1d0810c3aec078ae3ef0424c3c15" [[package]] name = "humantime-serde" @@ -925,11 +926,11 @@ [[package]] name = "indicatif" -version = "0.18.4" +version = "0.18.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25470f23803092da7d239834776d653104d551bc4d7eacaf31e6837854b8e9eb" +checksum = "9433806cd6b4ec1aba79c021c7e4c58fb4c3b9977c085062e611ac929998fb0c" dependencies = [ - "console 0.16.3", + "console 0.16.4", "portable-atomic", "unicode-width", "unit-prefix", @@ -966,9 +967,9 @@ [[package]] name = "js-sys" -version = "0.3.102" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" dependencies = [ "cfg-if", "futures-util", @@ -1036,15 +1037,15 @@ [[package]] name = "memchr" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "memmap2" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" +checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" dependencies = [ "libc", ] @@ -1217,9 +1218,9 @@ [[package]] name = "quote" -version = "1.0.45" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" dependencies = [ "proc-macro2", ] @@ -1248,9 +1249,9 @@ [[package]] name = "rand" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" dependencies = [ "chacha20", "getrandom 0.4.3", @@ -1408,11 +1409,11 @@ [[package]] name = "rmz" -version = "3.1.7" +version = "3.2.0" dependencies = [ "clap", "criterion", - "error-stack 0.7.1", + "error-stack 0.8.0", "ftzz", "fuc_engine", "indicatif", @@ -1505,9 +1506,9 @@ [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "same-file" @@ -2109,9 +2110,9 @@ [[package]] name = "wasm-bindgen" -version = "0.2.125" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" dependencies = [ "cfg-if", "once_cell", @@ -2122,9 +2123,9 @@ [[package]] name = "wasm-bindgen-macro" -version = "0.2.125" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2132,9 +2133,9 @@ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.125" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" dependencies = [ "bumpalo", "proc-macro2", @@ -2145,18 +2146,18 @@ [[package]] name = "wasm-bindgen-shared" -version = "0.2.125" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.102" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6430a72df5eb332242960fe84b3002a241163998241eb596d4f739b9757061d" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" dependencies = [ "js-sys", "wasm-bindgen", @@ -2335,18 +2336,18 @@ [[package]] name = "zerocopy" -version = "0.8.52" +version = "0.8.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" +checksum = "b7cbbc0a705a0fd05cc3676525980d2bf5a9bc4adac6d6475209a7887cf59d19" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.52" +version = "0.8.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" +checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5" dependencies = [ "proc-macro2", "quote", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fuc-3.1.7/Cargo.toml new/fuc-3.2.0/Cargo.toml --- old/fuc-3.1.7/Cargo.toml 2026-06-22 01:20:22.000000000 +0200 +++ new/fuc-3.2.0/Cargo.toml 2026-07-13 02:21:11.000000000 +0200 @@ -13,7 +13,7 @@ ] [workspace.package] -version = "3.1.7" +version = "3.2.0" authors = ["Alex Saveau <[email protected]>"] edition = "2024" repository = "https://github.com/SUPERCILEX/fuc" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fuc-3.1.7/cpz/Cargo.toml new/fuc-3.2.0/cpz/Cargo.toml --- old/fuc-3.1.7/cpz/Cargo.toml 2026-06-22 01:20:22.000000000 +0200 +++ new/fuc-3.2.0/cpz/Cargo.toml 2026-07-13 02:21:11.000000000 +0200 @@ -12,9 +12,9 @@ [dependencies] clap = { version = "4.6.1", features = ["derive", "wrap_help"] } -error-stack = { version = "0.7.1", default-features = false, features = ["std"] } +error-stack = { version = "0.8.0", default-features = false, features = ["std"] } fuc_engine = { version = "3", path = "../fuc_engine" } -indicatif = { version = "0.18.4", optional = true } +indicatif = { version = "0.18.6", optional = true } thiserror = "2.0.18" tracing = { version = "0.1.44", optional = true } tracing-indicatif = { version = "0.3.14", optional = true } @@ -25,8 +25,8 @@ [dev-dependencies] cache-size = "0.7.0" criterion = "0.8.2" -memmap2 = "0.9.10" -rand = "0.10.1" +memmap2 = "0.9.11" +rand = "0.10.2" supercilex-tests = { version = "0.4.22", default-features = false, features = ["clap"] } tempfile = "3.27.0" trycmd = "1.2.0" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fuc-3.1.7/fuc_engine/Cargo.toml new/fuc-3.2.0/fuc_engine/Cargo.toml --- old/fuc-3.1.7/fuc_engine/Cargo.toml 2026-06-22 01:20:22.000000000 +0200 +++ new/fuc-3.2.0/fuc_engine/Cargo.toml 2026-07-13 02:21:11.000000000 +0200 @@ -13,12 +13,12 @@ [dependencies] bon = "3.9.3" once_cell = "1.21.3" -crossbeam-channel = "0.5.15" +crossbeam-channel = "0.5.16" thiserror = "2.0.18" tracing = { version = "0.1.44", default-features = false, features = ["attributes"], optional = true } [target.'cfg(target_os = "linux")'.dependencies] -rustix = { version = "1.1.4", features = ["fs", "thread", "linux_latest"] } +rustix = { version = "1.1.4", features = ["fs", "thread", "mm", "linux_latest"] } [target.'cfg(not(target_os = "linux"))'.dependencies] rayon = "1.12.0" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fuc-3.1.7/fuc_engine/api.golden new/fuc-3.2.0/fuc_engine/api.golden --- old/fuc-3.1.7/fuc_engine/api.golden 2026-06-22 01:20:22.000000000 +0200 +++ new/fuc-3.2.0/fuc_engine/api.golden 2026-07-13 02:21:11.000000000 +0200 @@ -6,7 +6,7 @@ pub fuc_engine::Error::Internal pub fuc_engine::Error::Io pub fuc_engine::Error::Io::context: alloc::borrow::Cow<'static, str> -pub fuc_engine::Error::Io::error: std::io::error::Error +pub fuc_engine::Error::Io::error: core::io::error::Error pub fuc_engine::Error::Join pub fuc_engine::Error::NotFound pub fuc_engine::Error::NotFound::file: std::path::PathBuf diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fuc-3.1.7/fuc_engine/src/ops/copy.rs new/fuc-3.2.0/fuc_engine/src/ops/copy.rs --- old/fuc-3.1.7/fuc_engine/src/ops/copy.rs 2026-06-22 01:20:22.000000000 +0200 +++ new/fuc-3.2.0/fuc_engine/src/ops/copy.rs 2026-07-13 02:21:11.000000000 +0200 @@ -273,7 +273,8 @@ let mut threads = Vec::with_capacity(available_parallelism); { - let mut buf = [MaybeUninit::<u8>::uninit(); 8192]; + #[allow(clippy::large_stack_arrays)] + let mut buf = [MaybeUninit::<u8>::uninit(); 32768]; let symlink_buf_cache = Cell::new(Vec::new()); for node in &tasks { let mut maybe_spawn = || { @@ -318,7 +319,8 @@ ) -> Result<(), Error> { unshare_files()?; - let mut buf = [MaybeUninit::<u8>::uninit(); 8192]; + #[allow(clippy::large_stack_arrays)] + let mut buf = [MaybeUninit::<u8>::uninit(); 32768]; let symlink_buf_cache = Cell::new(Vec::new()); for node in tasks { copy_dir::<HARD_LINK>(node, follow_symlinks, &mut buf, &symlink_buf_cache, || {})?; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fuc-3.1.7/fuc_engine/src/ops/remove.rs new/fuc-3.2.0/fuc_engine/src/ops/remove.rs --- old/fuc-3.1.7/fuc_engine/src/ops/remove.rs 2026-06-22 01:20:22.000000000 +0200 +++ new/fuc-3.2.0/fuc_engine/src/ops/remove.rs 2026-07-13 02:21:11.000000000 +0200 @@ -123,11 +123,15 @@ fs, mem::MaybeUninit, num::NonZeroUsize, + ops::{Deref, DerefMut}, os::{ fd::{AsFd, OwnedFd}, unix::ffi::OsStrExt, }, path::{Path, PathBuf}, + ptr, + ptr::NonNull, + slice, sync::Arc, thread, thread::JoinHandle, @@ -138,6 +142,7 @@ use rustix::{ fs::{AtFlags, CWD, FileType, Mode, OFlags, RawDir, openat, unlinkat}, io::Errno, + mm::{MapFlags, ProtFlags, mmap_anonymous, munmap}, thread::{UnshareFlags, unshare_unsafe}, }; @@ -188,6 +193,50 @@ } } + #[derive(Debug)] + pub struct DirBuf { + ptr: NonNull<u8>, + len: usize, + } + + impl DirBuf { + pub fn new() -> rustix::io::Result<Self> { + let len = 16 * (1 << 20); + Ok(Self { + ptr: unsafe { + NonNull::new_unchecked(mmap_anonymous( + ptr::null_mut(), + len, + ProtFlags::READ | ProtFlags::WRITE, + MapFlags::PRIVATE | MapFlags::NORESERVE, + )?) + } + .cast(), + len, + }) + } + } + + impl Deref for DirBuf { + type Target = [MaybeUninit<u8>]; + + fn deref(&self) -> &[MaybeUninit<u8>] { + unsafe { slice::from_raw_parts(self.ptr.as_ptr().cast(), self.len) } + } + } + + impl DerefMut for DirBuf { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr().cast(), self.len) } + } + } + + impl Drop for DirBuf { + fn drop(&mut self) { + let _ = unsafe { munmap(self.ptr.as_ptr().cast(), self.len) }; + } + } + fn unshare_io() -> Result<(), Error> { if env::var_os("NO_UNSHARE").is_none() { unsafe { unshare_unsafe(UnshareFlags::FILES | UnshareFlags::FS) } @@ -207,7 +256,7 @@ let mut threads = Vec::with_capacity(available_parallelism); { - let mut buf = [MaybeUninit::<u8>::uninit(); 8192]; + let mut buf = DirBuf::new().map_io_err(|| "Failed to allocate dir buf.")?; for message in &tasks { let mut maybe_spawn = || { if available_parallelism > 0 && !tasks.is_empty() { @@ -242,7 +291,7 @@ fn worker_thread(tasks: Receiver<TreeNode>) -> Result<(), Error> { unshare_io()?; - let mut buf = [MaybeUninit::<u8>::uninit(); 8192]; + let mut buf = DirBuf::new().map_io_err(|| "Failed to allocate dir buf.")?; for message in tasks { delete_dir(message, &mut buf, || {})?; } @@ -254,19 +303,28 @@ tracing::instrument(level = "info", skip(buf, maybe_spawn)) )] fn delete_dir( - node: TreeNode, + mut node: TreeNode, buf: &mut [MaybeUninit<u8>], - maybe_spawn: impl FnMut(), + mut maybe_spawn: impl FnMut(), ) -> Result<(), Error> { - let dir = openat( - CWD, - &node.path, - OFlags::RDONLY | OFlags::DIRECTORY | OFlags::NOFOLLOW, - Mode::empty(), - ) - .map_io_err(|| format!("Failed to open directory: {:?}", node.path))?; - let node = delete_dir_contents(node, dir, buf, maybe_spawn)?; - delete_empty_dir_chain(node) + // This retry loop is pretty cursed. All popular Linux file systems handle + // getdents64 and unlink interleavings correctly, but it's technically not POSIX + // compliant and thus can fail. We catch the failures by hanlding directory + // NOTEMPTY errors. + loop { + let dir = openat( + CWD, + &node.path, + OFlags::RDONLY | OFlags::DIRECTORY | OFlags::NOFOLLOW, + Mode::empty(), + ) + .map_io_err(|| format!("Failed to open directory: {:?}", node.path))?; + let node_ = delete_dir_contents(node, dir, buf, &mut maybe_spawn)?; + match delete_empty_dir_chain(node_)? { + UnlinkDirOutcome::Ok => return Ok(()), + UnlinkDirOutcome::DirNotEmpty(node_) => node = node_, + } + } } #[cfg_attr( @@ -360,22 +418,31 @@ Ok(Arcable::into_inner(node)) } + enum UnlinkDirOutcome { + Ok, + DirNotEmpty(TreeNode), + } + #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace"))] - fn delete_empty_dir_chain(mut node: Option<TreeNode>) -> Result<(), Error> { + fn delete_empty_dir_chain(mut node: Option<TreeNode>) -> Result<UnlinkDirOutcome, Error> { let mut result = Ok(()); - while let Some(TreeNode { - ref path, - parent, - messages: _, - }) = node - { + while let Some(node_) = node { if result.is_ok() { - result = unlinkat(CWD, path, AtFlags::REMOVEDIR) - .map_io_err(|| format!("Failed to delete directory: {path:?}")); + // We don't use ? here and also don't break out of the loop so that we continue + // to drain the linked list without overflowing the drop stack + match unlinkat(CWD, &node_.path, AtFlags::REMOVEDIR) { + Err(Errno::NOTEMPTY) => { + return Ok(UnlinkDirOutcome::DirNotEmpty(node_)); + } + r => { + result = r + .map_io_err(|| format!("Failed to delete directory: {:?}", node_.path)); + } + } } - node = parent.and_then(Arc::into_inner); + node = node_.parent.and_then(Arc::into_inner); } - result + result.map(|()| UnlinkDirOutcome::Ok) } #[cfg_attr(feature = "tracing", tracing::instrument(level = "debug", skip(dir)))] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fuc-3.1.7/rmz/Cargo.toml new/fuc-3.2.0/rmz/Cargo.toml --- old/fuc-3.1.7/rmz/Cargo.toml 2026-06-22 01:20:22.000000000 +0200 +++ new/fuc-3.2.0/rmz/Cargo.toml 2026-07-13 02:21:11.000000000 +0200 @@ -12,9 +12,9 @@ [dependencies] clap = { version = "4.6.1", features = ["derive", "wrap_help"] } -error-stack = { version = "0.7.1", default-features = false, features = ["std"] } +error-stack = { version = "0.8.0", default-features = false, features = ["std"] } fuc_engine = { version = "3", path = "../fuc_engine" } -indicatif = { version = "0.18.4", optional = true } +indicatif = { version = "0.18.6", optional = true } thiserror = "2.0.18" tracing = { version = "0.1.44", optional = true } tracing-indicatif = { version = "0.3.14", optional = true } ++++++ fuc.obsinfo ++++++ --- /var/tmp/diff_new_pack.IHESPU/_old 2026-07-14 13:50:33.596280571 +0200 +++ /var/tmp/diff_new_pack.IHESPU/_new 2026-07-14 13:50:33.608280984 +0200 @@ -1,5 +1,5 @@ name: fuc -version: 3.1.7 -mtime: 1782084022 -commit: ece8652ac326fbe79e17b4381342ccf95c682684 +version: 3.2.0 +mtime: 1783902071 +commit: 3aa8b04f1af491dfdb631b89a876db518bd6a363 ++++++ vendor.tar.zst ++++++ /work/SRC/openSUSE:Factory/fuc/vendor.tar.zst /work/SRC/openSUSE:Factory/.fuc.new.1991/vendor.tar.zst differ: char 7, line 1
