mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 03:27:44 +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 }
|
clap = { workspace = true }
|
||||||
fs_extra = { workspace = true }
|
fs_extra = { workspace = true }
|
||||||
indicatif = { workspace = true }
|
indicatif = { workspace = true }
|
||||||
|
libc = { workspace = true }
|
||||||
|
thiserror = { workspace = true }
|
||||||
uucore = { workspace = true, features = [
|
uucore = { workspace = true, features = [
|
||||||
"backup-control",
|
"backup-control",
|
||||||
"fs",
|
"fs",
|
||||||
"fsxattr",
|
"fsxattr",
|
||||||
"update-control",
|
"update-control",
|
||||||
] }
|
] }
|
||||||
thiserror = { workspace = true }
|
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
windows-sys = { workspace = true, features = [
|
windows-sys = { workspace = true, features = [
|
||||||
|
|
|
@ -10,6 +10,7 @@ mod error;
|
||||||
use clap::builder::ValueParser;
|
use clap::builder::ValueParser;
|
||||||
use clap::{Arg, ArgAction, ArgMatches, Command, error::ErrorKind};
|
use clap::{Arg, ArgAction, ArgMatches, Command, error::ErrorKind};
|
||||||
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
|
@ -17,12 +18,17 @@ use std::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use std::os::unix;
|
use std::os::unix;
|
||||||
|
#[cfg(unix)]
|
||||||
|
use std::os::unix::fs::FileTypeExt;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use std::os::windows;
|
use std::os::windows;
|
||||||
use std::path::{Path, PathBuf, absolute};
|
use std::path::{Path, PathBuf, absolute};
|
||||||
|
|
||||||
use uucore::backup_control::{self, source_is_target_backup};
|
use uucore::backup_control::{self, source_is_target_backup};
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{FromIo, UResult, USimpleError, UUsageError, set_exit_code};
|
use uucore::error::{FromIo, UResult, USimpleError, UUsageError, set_exit_code};
|
||||||
|
#[cfg(unix)]
|
||||||
|
use uucore::fs::make_fifo;
|
||||||
use uucore::fs::{
|
use uucore::fs::{
|
||||||
MissingHandling, ResolveMode, are_hardlinks_or_one_way_symlink_to_same_file,
|
MissingHandling, ResolveMode, are_hardlinks_or_one_way_symlink_to_same_file,
|
||||||
are_hardlinks_to_same_file, canonicalize, path_ends_with_terminator,
|
are_hardlinks_to_same_file, canonicalize, path_ends_with_terminator,
|
||||||
|
@ -665,6 +671,16 @@ fn rename(
|
||||||
Ok(())
|
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
|
/// A wrapper around `fs::rename`, so that if it fails, we try falling back on
|
||||||
/// copying and removing.
|
/// copying and removing.
|
||||||
fn rename_with_fallback(
|
fn rename_with_fallback(
|
||||||
|
@ -694,12 +710,28 @@ fn rename_with_fallback(
|
||||||
rename_symlink_fallback(from, to)
|
rename_symlink_fallback(from, to)
|
||||||
} else if file_type.is_dir() {
|
} else if file_type.is_dir() {
|
||||||
rename_dir_fallback(from, to, multi_progress)
|
rename_dir_fallback(from, to, multi_progress)
|
||||||
|
} else if is_fifo(file_type) {
|
||||||
|
rename_fifo_fallback(from, to)
|
||||||
} else {
|
} else {
|
||||||
rename_file_fallback(from, to)
|
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
|
/// Move the given symlink to the given destination. On Windows, dangling
|
||||||
/// symlinks return an error.
|
/// symlinks return an error.
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
use filetime::FileTime;
|
use filetime::FileTime;
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
use std::path::Path;
|
||||||
use uutests::new_ucmd;
|
use uutests::new_ucmd;
|
||||||
use uutests::util::TestScenario;
|
use uutests::util::TestScenario;
|
||||||
use uutests::{at_and_ucmd, util_name};
|
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 'a': No such file or directory")
|
||||||
.stderr_contains("mv: cannot stat 'b/': 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