1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

Merge pull request #7775 from jfinkels/cp-make-fifo-uucore

cp: factor make_fifo() function out to uucore::fs
This commit is contained in:
jfinkels 2025-04-19 05:40:29 -04:00 committed by GitHub
parent 74e353dec0
commit 3965bc5b9e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 61 additions and 14 deletions

View file

@ -7,14 +7,10 @@
use quick_error::quick_error;
use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
#[cfg(not(windows))]
use std::ffi::CString;
use std::ffi::OsString;
use std::fs::{self, Metadata, OpenOptions, Permissions};
use std::io;
#[cfg(unix)]
use std::os::unix::ffi::OsStrExt;
#[cfg(unix)]
use std::os::unix::fs::{FileTypeExt, PermissionsExt};
use std::path::{Path, PathBuf, StripPrefixError};
#[cfg(all(unix, not(target_os = "android")))]
@ -23,13 +19,13 @@ use uucore::fsxattr::copy_xattrs;
use clap::{Arg, ArgAction, ArgMatches, Command, builder::ValueParser};
use filetime::FileTime;
use indicatif::{ProgressBar, ProgressStyle};
#[cfg(unix)]
use libc::mkfifo;
use quick_error::ResultExt;
use platform::copy_on_write;
use uucore::display::Quotable;
use uucore::error::{UClapError, UError, UResult, UUsageError, set_exit_code};
#[cfg(unix)]
use uucore::fs::make_fifo;
use uucore::fs::{
FileInformation, MissingHandling, ResolveMode, are_hardlinks_to_same_file, canonicalize,
get_filename, is_symlink_loop, normalize_path, path_ends_with_terminator,
@ -2534,12 +2530,7 @@ fn copy_fifo(dest: &Path, overwrite: OverwriteMode, debug: bool) -> CopyResult<(
fs::remove_file(dest)?;
}
let name = CString::new(dest.as_os_str().as_bytes()).unwrap();
let err = unsafe { mkfifo(name.as_ptr(), 0o666) };
if err == -1 {
return Err(format!("cannot create fifo {}: File exists", dest.quote()).into());
}
Ok(())
make_fifo(dest).map_err(|_| format!("cannot create fifo {}: File exists", dest.quote()).into())
}
fn copy_link(

View file

@ -3,7 +3,7 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//! Set of functions to manage files and symlinks
//! Set of functions to manage regular files, special files, and links.
// spell-checker:ignore backport
@ -11,11 +11,13 @@
use libc::{
S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFLNK, S_IFMT, S_IFREG, S_IFSOCK, S_IRGRP, S_IROTH,
S_IRUSR, S_ISGID, S_ISUID, S_ISVTX, S_IWGRP, S_IWOTH, S_IWUSR, S_IXGRP, S_IXOTH, S_IXUSR,
mode_t,
mkfifo, mode_t,
};
use std::collections::HashSet;
use std::collections::VecDeque;
use std::env;
#[cfg(unix)]
use std::ffi::CString;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::fs::read_dir;
@ -798,6 +800,37 @@ pub fn get_filename(file: &Path) -> Option<&str> {
file.file_name().and_then(|filename| filename.to_str())
}
/// Make a FIFO, also known as a named pipe.
///
/// This is a safe wrapper for the unsafe [`libc::mkfifo`] function,
/// which makes a [named
/// pipe](https://en.wikipedia.org/wiki/Named_pipe) on Unix systems.
///
/// # Errors
///
/// If the named pipe cannot be created.
///
/// # Examples
///
/// ```ignore
/// use uucore::fs::make_fifo;
///
/// make_fifo("my-pipe").expect("failed to create the named pipe");
///
/// std::thread::spawn(|| { std::fs::write("my-pipe", b"hello").unwrap(); });
/// assert_eq!(std::fs::read("my-pipe").unwrap(), b"hello");
/// ```
#[cfg(unix)]
pub fn make_fifo(path: &Path) -> std::io::Result<()> {
let name = CString::new(path.to_str().unwrap()).unwrap();
let err = unsafe { mkfifo(name.as_ptr(), 0o666) };
if err == -1 {
Err(std::io::Error::from_raw_os_error(err))
} else {
Ok(())
}
}
#[cfg(test)]
mod tests {
// Note this useful idiom: importing names from outer (for mod tests) scope.
@ -807,6 +840,8 @@ mod tests {
#[cfg(unix)]
use std::os::unix;
#[cfg(unix)]
use std::os::unix::fs::FileTypeExt;
#[cfg(unix)]
use tempfile::{NamedTempFile, tempdir};
struct NormalizePathTestCase<'a> {
@ -1039,4 +1074,25 @@ mod tests {
let file_path = PathBuf::from("~/foo.txt");
assert!(matches!(get_filename(&file_path), Some("foo.txt")));
}
#[cfg(unix)]
#[test]
fn test_make_fifo() {
// Create the FIFO in a temporary directory.
let tempdir = tempdir().unwrap();
let path = tempdir.path().join("f");
assert!(make_fifo(&path).is_ok());
// Check that it is indeed a FIFO.
assert!(std::fs::metadata(&path).unwrap().file_type().is_fifo());
// Check that we can write to it and read from it.
//
// Write and read need to happen in different threads,
// otherwise `write` would block indefinitely while waiting
// for the `read`.
let path2 = path.clone();
std::thread::spawn(move || assert!(std::fs::write(&path2, b"foo").is_ok()));
assert_eq!(std::fs::read(&path).unwrap(), b"foo");
}
}