mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-27 19:17:43 +00:00
mv: fix moving FIFO to a different filesystem
Fix a bug in `mv` where it would hang indefinitely while trying to copy a FIFO across filesystems. The solution is to remove the old FIFO and create a new one on the new filesystem. Fixes #7076
This commit is contained in:
parent
1d89ea5b6d
commit
2717f9c8b5
3 changed files with 51 additions and 1 deletions
|
@ -21,13 +21,14 @@ path = "src/mv.rs"
|
|||
clap = { workspace = true }
|
||||
fs_extra = { workspace = true }
|
||||
indicatif = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
uucore = { workspace = true, features = [
|
||||
"backup-control",
|
||||
"fs",
|
||||
"fsxattr",
|
||||
"update-control",
|
||||
] }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows-sys = { workspace = true, features = [
|
||||
|
|
|
@ -10,6 +10,7 @@ mod error;
|
|||
use clap::builder::ValueParser;
|
||||
use clap::{Arg, ArgAction, ArgMatches, Command, error::ErrorKind};
|
||||
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
|
@ -17,12 +18,17 @@ use std::fs;
|
|||
use std::io;
|
||||
#[cfg(unix)]
|
||||
use std::os::unix;
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::FileTypeExt;
|
||||
#[cfg(windows)]
|
||||
use std::os::windows;
|
||||
use std::path::{Path, PathBuf, absolute};
|
||||
|
||||
use uucore::backup_control::{self, source_is_target_backup};
|
||||
use uucore::display::Quotable;
|
||||
use uucore::error::{FromIo, UResult, USimpleError, UUsageError, set_exit_code};
|
||||
#[cfg(unix)]
|
||||
use uucore::fs::make_fifo;
|
||||
use uucore::fs::{
|
||||
MissingHandling, ResolveMode, are_hardlinks_or_one_way_symlink_to_same_file,
|
||||
are_hardlinks_to_same_file, canonicalize, path_ends_with_terminator,
|
||||
|
@ -665,6 +671,16 @@ fn rename(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn is_fifo(filetype: fs::FileType) -> bool {
|
||||
filetype.is_fifo()
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
fn is_fifo(_filetype: fs::FileType) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// A wrapper around `fs::rename`, so that if it fails, we try falling back on
|
||||
/// copying and removing.
|
||||
fn rename_with_fallback(
|
||||
|
@ -694,12 +710,28 @@ fn rename_with_fallback(
|
|||
rename_symlink_fallback(from, to)
|
||||
} else if file_type.is_dir() {
|
||||
rename_dir_fallback(from, to, multi_progress)
|
||||
} else if is_fifo(file_type) {
|
||||
rename_fifo_fallback(from, to)
|
||||
} else {
|
||||
rename_file_fallback(from, to)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Replace the destination with a new pipe with the same name as the source.
|
||||
#[cfg(unix)]
|
||||
fn rename_fifo_fallback(from: &Path, to: &Path) -> io::Result<()> {
|
||||
if to.try_exists()? {
|
||||
fs::remove_file(to)?;
|
||||
}
|
||||
make_fifo(to).and_then(|_| fs::remove_file(from))
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
fn rename_fifo_fallback(_from: &Path, _to: &Path) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Move the given symlink to the given destination. On Windows, dangling
|
||||
/// symlinks return an error.
|
||||
#[cfg(unix)]
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
use filetime::FileTime;
|
||||
use rstest::rstest;
|
||||
use std::io::Write;
|
||||
#[cfg(not(windows))]
|
||||
use std::path::Path;
|
||||
use uutests::new_ucmd;
|
||||
use uutests::util::TestScenario;
|
||||
use uutests::{at_and_ucmd, util_name};
|
||||
|
@ -1876,3 +1878,18 @@ fn test_mv_error_msg_with_multiple_sources_that_does_not_exist() {
|
|||
.stderr_contains("mv: cannot stat 'a': No such file or directory")
|
||||
.stderr_contains("mv: cannot stat 'b/': No such file or directory");
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
#[ignore = "requires access to a different filesystem"]
|
||||
#[test]
|
||||
fn test_special_file_different_filesystem() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.mkfifo("f");
|
||||
// TODO Use `TestScenario::mount_temp_fs()` for this purpose and
|
||||
// un-ignore this test.
|
||||
std::fs::create_dir("/dev/shm/tmp").unwrap();
|
||||
ucmd.args(&["f", "/dev/shm/tmp"]).succeeds().no_output();
|
||||
assert!(!at.file_exists("f"));
|
||||
assert!(Path::new("/dev/shm/tmp/f").exists());
|
||||
std::fs::remove_dir_all("/dev/shm/tmp").unwrap();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue