Skip to content

Commit 3965bc5

Browse files
authored
Merge pull request #7775 from jfinkels/cp-make-fifo-uucore
cp: factor make_fifo() function out to uucore::fs
1 parent 74e353d commit 3965bc5

File tree

2 files changed

+61
-14
lines changed

2 files changed

+61
-14
lines changed

src/uu/cp/src/cp.rs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,10 @@
77
use quick_error::quick_error;
88
use std::cmp::Ordering;
99
use std::collections::{HashMap, HashSet};
10-
#[cfg(not(windows))]
11-
use std::ffi::CString;
1210
use std::ffi::OsString;
1311
use std::fs::{self, Metadata, OpenOptions, Permissions};
1412
use std::io;
1513
#[cfg(unix)]
16-
use std::os::unix::ffi::OsStrExt;
17-
#[cfg(unix)]
1814
use std::os::unix::fs::{FileTypeExt, PermissionsExt};
1915
use std::path::{Path, PathBuf, StripPrefixError};
2016
#[cfg(all(unix, not(target_os = "android")))]
@@ -23,13 +19,13 @@ use uucore::fsxattr::copy_xattrs;
2319
use clap::{Arg, ArgAction, ArgMatches, Command, builder::ValueParser};
2420
use filetime::FileTime;
2521
use indicatif::{ProgressBar, ProgressStyle};
26-
#[cfg(unix)]
27-
use libc::mkfifo;
2822
use quick_error::ResultExt;
2923

3024
use platform::copy_on_write;
3125
use uucore::display::Quotable;
3226
use uucore::error::{UClapError, UError, UResult, UUsageError, set_exit_code};
27+
#[cfg(unix)]
28+
use uucore::fs::make_fifo;
3329
use uucore::fs::{
3430
FileInformation, MissingHandling, ResolveMode, are_hardlinks_to_same_file, canonicalize,
3531
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<(
25342530
fs::remove_file(dest)?;
25352531
}
25362532

2537-
let name = CString::new(dest.as_os_str().as_bytes()).unwrap();
2538-
let err = unsafe { mkfifo(name.as_ptr(), 0o666) };
2539-
if err == -1 {
2540-
return Err(format!("cannot create fifo {}: File exists", dest.quote()).into());
2541-
}
2542-
Ok(())
2533+
make_fifo(dest).map_err(|_| format!("cannot create fifo {}: File exists", dest.quote()).into())
25432534
}
25442535

25452536
fn copy_link(

src/uucore/src/lib/features/fs.rs

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,21 @@
33
// For the full copyright and license information, please view the LICENSE
44
// file that was distributed with this source code.
55

6-
//! Set of functions to manage files and symlinks
6+
//! Set of functions to manage regular files, special files, and links.
77
88
// spell-checker:ignore backport
99

1010
#[cfg(unix)]
1111
use libc::{
1212
S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFLNK, S_IFMT, S_IFREG, S_IFSOCK, S_IRGRP, S_IROTH,
1313
S_IRUSR, S_ISGID, S_ISUID, S_ISVTX, S_IWGRP, S_IWOTH, S_IWUSR, S_IXGRP, S_IXOTH, S_IXUSR,
14-
mode_t,
14+
mkfifo, mode_t,
1515
};
1616
use std::collections::HashSet;
1717
use std::collections::VecDeque;
1818
use std::env;
19+
#[cfg(unix)]
20+
use std::ffi::CString;
1921
use std::ffi::{OsStr, OsString};
2022
use std::fs;
2123
use std::fs::read_dir;
@@ -798,6 +800,37 @@ pub fn get_filename(file: &Path) -> Option<&str> {
798800
file.file_name().and_then(|filename| filename.to_str())
799801
}
800802

803+
/// Make a FIFO, also known as a named pipe.
804+
///
805+
/// This is a safe wrapper for the unsafe [`libc::mkfifo`] function,
806+
/// which makes a [named
807+
/// pipe](https://en.wikipedia.org/wiki/Named_pipe) on Unix systems.
808+
///
809+
/// # Errors
810+
///
811+
/// If the named pipe cannot be created.
812+
///
813+
/// # Examples
814+
///
815+
/// ```ignore
816+
/// use uucore::fs::make_fifo;
817+
///
818+
/// make_fifo("my-pipe").expect("failed to create the named pipe");
819+
///
820+
/// std::thread::spawn(|| { std::fs::write("my-pipe", b"hello").unwrap(); });
821+
/// assert_eq!(std::fs::read("my-pipe").unwrap(), b"hello");
822+
/// ```
823+
#[cfg(unix)]
824+
pub fn make_fifo(path: &Path) -> std::io::Result<()> {
825+
let name = CString::new(path.to_str().unwrap()).unwrap();
826+
let err = unsafe { mkfifo(name.as_ptr(), 0o666) };
827+
if err == -1 {
828+
Err(std::io::Error::from_raw_os_error(err))
829+
} else {
830+
Ok(())
831+
}
832+
}
833+
801834
#[cfg(test)]
802835
mod tests {
803836
// Note this useful idiom: importing names from outer (for mod tests) scope.
@@ -807,6 +840,8 @@ mod tests {
807840
#[cfg(unix)]
808841
use std::os::unix;
809842
#[cfg(unix)]
843+
use std::os::unix::fs::FileTypeExt;
844+
#[cfg(unix)]
810845
use tempfile::{NamedTempFile, tempdir};
811846

812847
struct NormalizePathTestCase<'a> {
@@ -1039,4 +1074,25 @@ mod tests {
10391074
let file_path = PathBuf::from("~/foo.txt");
10401075
assert!(matches!(get_filename(&file_path), Some("foo.txt")));
10411076
}
1077+
1078+
#[cfg(unix)]
1079+
#[test]
1080+
fn test_make_fifo() {
1081+
// Create the FIFO in a temporary directory.
1082+
let tempdir = tempdir().unwrap();
1083+
let path = tempdir.path().join("f");
1084+
assert!(make_fifo(&path).is_ok());
1085+
1086+
// Check that it is indeed a FIFO.
1087+
assert!(std::fs::metadata(&path).unwrap().file_type().is_fifo());
1088+
1089+
// Check that we can write to it and read from it.
1090+
//
1091+
// Write and read need to happen in different threads,
1092+
// otherwise `write` would block indefinitely while waiting
1093+
// for the `read`.
1094+
let path2 = path.clone();
1095+
std::thread::spawn(move || assert!(std::fs::write(&path2, b"foo").is_ok()));
1096+
assert_eq!(std::fs::read(&path).unwrap(), b"foo");
1097+
}
10421098
}

0 commit comments

Comments
 (0)