From 2c3f8d87c41980c8ea5d75676011c09d9d727b88 Mon Sep 17 00:00:00 2001
From: Sebastian Thiel <sebastian.thiel@icloud.com>
Date: Sun, 22 Dec 2024 19:05:40 +0100
Subject: [PATCH] fix: assure possibly blocking non-files (like FIFOs) won't be
 picked up for publishing.

This would otherwise cause the publish to hang.
---
 src/cargo/sources/path.rs  |  8 ++++++--
 tests/testsuite/git.rs     | 31 +++++++++++++++++++++++++++++++
 tests/testsuite/package.rs | 29 +++++++++++++++++++++++++++++
 3 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/src/cargo/sources/path.rs b/src/cargo/sources/path.rs
index 7765906977f..ee2e6fea47f 100644
--- a/src/cargo/sources/path.rs
+++ b/src/cargo/sources/path.rs
@@ -626,8 +626,11 @@ fn list_files_gix(
         .filter(|res| {
             // Don't include Cargo.lock if it is untracked. Packaging will
             // generate a new one as needed.
+            // Also don't include untrackable directory entries, like FIFOs.
             res.as_ref().map_or(true, |item| {
-                !(item.entry.status == Status::Untracked && item.entry.rela_path == "Cargo.lock")
+                item.entry.disk_kind != Some(gix::dir::entry::Kind::Untrackable)
+                    && !(item.entry.status == Status::Untracked
+                        && item.entry.rela_path == "Cargo.lock")
             })
         })
         .map(|res| res.map(|item| (item.entry.rela_path, item.entry.disk_kind)))
@@ -751,7 +754,8 @@ fn list_files_walk(
     for entry in walkdir {
         match entry {
             Ok(entry) => {
-                if !entry.file_type().is_dir() {
+                let file_type = entry.file_type();
+                if file_type.is_file() || file_type.is_symlink() {
                     ret.push(entry.into_path());
                 }
             }
diff --git a/tests/testsuite/git.rs b/tests/testsuite/git.rs
index 40e9db15c86..7ccd08b7950 100644
--- a/tests/testsuite/git.rs
+++ b/tests/testsuite/git.rs
@@ -4221,3 +4221,34 @@ src/lib.rs
 "#]])
         .run();
 }
+
+#[cargo_test]
+#[cfg(unix)]
+fn simple_with_fifo() {
+    let git_project = git::new("foo", |project| {
+        project
+            .file(
+                "Cargo.toml",
+                r#"
+                [package]
+                name = "foo"
+                version = "0.1.0"
+                edition = "2015"
+            "#,
+            )
+            .file("src/main.rs", "fn main() {}")
+    });
+
+    std::process::Command::new("mkfifo")
+        .current_dir(git_project.root())
+        .arg(git_project.root().join("blocks-when-read"))
+        .status()
+        .expect("a FIFO can be created");
+
+    // Avoid actual blocking even in case of failure, assuming that what it lists here
+    // would also be read eventually.
+    git_project
+        .cargo("package -l")
+        .with_stdout_does_not_contain("blocks-when-read")
+        .run();
+}
diff --git a/tests/testsuite/package.rs b/tests/testsuite/package.rs
index 1740de4ac77..2ee3a2ef7d4 100644
--- a/tests/testsuite/package.rs
+++ b/tests/testsuite/package.rs
@@ -6873,3 +6873,32 @@ See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for
 "#]])
         .run();
 }
+
+#[cargo_test]
+#[cfg(unix)]
+fn simple_with_fifo() {
+    let p = project()
+        .file(
+            "Cargo.toml",
+            r#"
+                [package]
+                name = "foo"
+                version = "0.1.0"
+                edition = "2015"
+            "#,
+        )
+        .file("src/main.rs", "fn main() {}")
+        .build();
+
+    std::process::Command::new("mkfifo")
+        .current_dir(p.root())
+        .arg(p.root().join("blocks-when-read"))
+        .status()
+        .expect("a FIFO can be created");
+
+    // Avoid actual blocking even in case of failure, assuming that what it lists here
+    // would also be read eventually.
+    p.cargo("package -l")
+        .with_stdout_does_not_contain("blocks-when-read")
+        .run();
+}