cp: fix recursive socket file copy

This commit is contained in:
Anonymous-AAA
2025-08-13 08:25:34 +05:30
parent 005ccccddf
commit bfbdf10d3f
3 changed files with 62 additions and 5 deletions
+28 -1
View File
@@ -11,6 +11,8 @@ use std::fmt::Display;
use std::fs::{self, Metadata, OpenOptions, Permissions};
#[cfg(unix)]
use std::os::unix::fs::{FileTypeExt, PermissionsExt};
#[cfg(unix)]
use std::os::unix::net::UnixListener;
use std::path::{Path, PathBuf, StripPrefixError};
use std::{fmt, io};
#[cfg(all(unix, not(target_os = "android")))]
@@ -2071,6 +2073,7 @@ fn handle_copy_mode(
symlinked_files: &mut HashSet<FileInformation>,
source_in_command_line: bool,
source_is_fifo: bool,
source_is_socket: bool,
#[cfg(unix)] source_is_stream: bool,
) -> CopyResult<PerformedAction> {
let source_is_symlink = source_metadata.is_symlink();
@@ -2110,6 +2113,7 @@ fn handle_copy_mode(
context,
source_is_symlink,
source_is_fifo,
source_is_socket,
symlinked_files,
#[cfg(unix)]
source_is_stream,
@@ -2132,6 +2136,7 @@ fn handle_copy_mode(
context,
source_is_symlink,
source_is_fifo,
source_is_socket,
symlinked_files,
#[cfg(unix)]
source_is_stream,
@@ -2167,6 +2172,7 @@ fn handle_copy_mode(
context,
source_is_symlink,
source_is_fifo,
source_is_socket,
symlinked_files,
#[cfg(unix)]
source_is_stream,
@@ -2181,6 +2187,7 @@ fn handle_copy_mode(
context,
source_is_symlink,
source_is_fifo,
source_is_socket,
symlinked_files,
#[cfg(unix)]
source_is_stream,
@@ -2407,8 +2414,12 @@ fn copy_file(
#[cfg(unix)]
let source_is_fifo = source_metadata.file_type().is_fifo();
#[cfg(unix)]
let source_is_socket = source_metadata.file_type().is_socket();
#[cfg(not(unix))]
let source_is_fifo = false;
#[cfg(not(unix))]
let source_is_socket = false;
let source_is_stream = is_stream(&source_metadata);
@@ -2421,6 +2432,7 @@ fn copy_file(
symlinked_files,
source_in_command_line,
source_is_fifo,
source_is_socket,
#[cfg(unix)]
source_is_stream,
)?;
@@ -2547,6 +2559,7 @@ fn copy_helper(
context: &str,
source_is_symlink: bool,
source_is_fifo: bool,
source_is_socket: bool,
symlinked_files: &mut HashSet<FileInformation>,
#[cfg(unix)] source_is_stream: bool,
) -> CopyResult<()> {
@@ -2559,7 +2572,10 @@ fn copy_helper(
return Err(CpError::NotADirectory(dest.to_path_buf()));
}
if source_is_fifo && options.recursive && !options.copy_contents {
if source_is_socket && options.recursive && !options.copy_contents {
#[cfg(unix)]
copy_socket(dest, options.overwrite, options.debug)?;
} else if source_is_fifo && options.recursive && !options.copy_contents {
#[cfg(unix)]
copy_fifo(dest, options.overwrite, options.debug)?;
} else if source_is_symlink {
@@ -2596,6 +2612,17 @@ fn copy_fifo(dest: &Path, overwrite: OverwriteMode, debug: bool) -> CopyResult<(
.map_err(|_| translate!("cp-error-cannot-create-fifo", "path" => dest.quote()).into())
}
#[cfg(unix)]
fn copy_socket(dest: &Path, overwrite: OverwriteMode, debug: bool) -> CopyResult<()> {
if dest.exists() {
overwrite.verify(dest, debug)?;
fs::remove_file(dest)?;
}
UnixListener::bind(dest)?;
Ok(())
}
fn copy_link(
source: &Path,
dest: &Path,
+24 -3
View File
@@ -4,7 +4,7 @@
// file that was distributed with this source code.
// spell-checker:ignore (flags) reflink (fs) tmpfs (linux) rlimit Rlim NOFILE clob btrfs neve ROOTDIR USERDIR outfile uufs xattrs
// spell-checker:ignore bdfl hlsl IRWXO IRWXG nconfined matchpathcon libselinux-devel prwx doesnotexist reftests subdirs
// spell-checker:ignore bdfl hlsl IRWXO IRWXG nconfined matchpathcon libselinux-devel prwx doesnotexist reftests subdirs mksocket srwx
use uucore::display::Quotable;
#[cfg(feature = "feat_selinux")]
use uucore::selinux::get_getfattr_output;
@@ -18,10 +18,10 @@ use std::io::Write;
#[cfg(not(windows))]
use std::os::unix::fs;
#[cfg(unix)]
use std::os::unix::fs::MetadataExt;
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
#[cfg(unix)]
use std::os::unix::fs::{FileTypeExt, MetadataExt};
#[cfg(windows)]
use std::os::windows::fs::symlink_file;
#[cfg(not(windows))]
@@ -3105,6 +3105,27 @@ fn test_cp_fifo() {
assert_eq!(permission, "prwx-wx--x".to_string());
}
#[test]
#[cfg(unix)]
fn test_cp_socket() {
let (at, mut ucmd) = at_and_ucmd!();
at.mksocket("socket");
// Also test that permissions are preserved
at.set_mode("socket", 0o731);
ucmd.arg("--preserve=mode")
.arg("-r")
.arg("socket")
.arg("socket2")
.succeeds()
.no_stderr()
.no_stdout();
let metadata = std::fs::metadata(at.subdir.join("socket2")).unwrap();
let permission = uucore::fs::display_permissions(&metadata, true);
assert!(metadata.file_type().is_socket());
assert_eq!(permission, "srwx-wx--x".to_string());
}
#[cfg(all(unix, not(target_vendor = "apple")))]
fn find_other_group(current: u32) -> Option<u32> {
// Get the first group that doesn't match current
+10 -1
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.
//spell-checker: ignore (linux) rlimit prlimit coreutil ggroups uchild uncaptured scmd SHLVL canonicalized openpty
//spell-checker: ignore (linux) winsize xpixel ypixel setrlimit FSIZE SIGBUS SIGSEGV sigbus tmpfs
//spell-checker: ignore (linux) winsize xpixel ypixel setrlimit FSIZE SIGBUS SIGSEGV sigbus tmpfs mksocket
#![allow(dead_code)]
#![allow(
@@ -34,6 +34,8 @@ use std::os::fd::OwnedFd;
#[cfg(unix)]
use std::os::unix::fs::{PermissionsExt, symlink as symlink_dir, symlink as symlink_file};
#[cfg(unix)]
use std::os::unix::net::UnixListener;
#[cfg(unix)]
use std::os::unix::process::CommandExt;
#[cfg(unix)]
use std::os::unix::process::ExitStatusExt;
@@ -1132,6 +1134,13 @@ impl AtPath {
}
}
#[cfg(unix)]
pub fn mksocket(&self, socket: &str) {
let full_path = self.plus_as_string(socket);
log_info("mksocket", &full_path);
UnixListener::bind(full_path).expect("Socket file creation failed.");
}
#[cfg(not(windows))]
pub fn is_fifo(&self, fifo: &str) -> bool {
unsafe {