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

Merge pull request #2553 from miDeb/sort/race

sort: prevent race when deleting files
This commit is contained in:
Sylvestre Ledru 2021-08-22 22:49:57 +02:00 committed by GitHub
commit b828e922e5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 17 additions and 15 deletions

View file

@ -12,6 +12,7 @@
//! The buffers for the individual chunks are recycled. There are two buffers.
use std::cmp::Ordering;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::{
@ -238,7 +239,7 @@ fn read_write_loop<I: WriteableTmpFile>(
let tmp_file = write::<I>(
&mut chunk,
tmp_dir.next_file_path()?,
tmp_dir.next_file()?,
settings.compress_prog.as_deref(),
separator,
)?;
@ -268,7 +269,7 @@ fn read_write_loop<I: WriteableTmpFile>(
/// `compress_prog` is used to optionally compress file contents.
fn write<I: WriteableTmpFile>(
chunk: &mut Chunk,
file: PathBuf,
file: (File, PathBuf),
compress_prog: Option<&str>,
separator: u8,
) -> UResult<I::Closed> {

View file

@ -46,7 +46,7 @@ fn replace_output_file_in_input_files(
if let Some(copy) = &copy {
*file = copy.clone().into_os_string();
} else {
let copy_path = tmp_dir.next_file_path()?;
let (_file, copy_path) = tmp_dir.next_file()?;
std::fs::copy(file_path, &copy_path)
.map_err(|error| SortError::OpenTmpFileFailed { error })?;
*file = copy_path.clone().into_os_string();
@ -110,7 +110,7 @@ pub fn merge_with_file_limit<
remaining_files = remaining_files.saturating_sub(settings.merge_batch_size);
let merger = merge_without_limit(batches.next().unwrap(), settings)?;
let mut tmp_file =
Tmp::create(tmp_dir.next_file_path()?, settings.compress_prog.as_deref())?;
Tmp::create(tmp_dir.next_file()?, settings.compress_prog.as_deref())?;
merger.write_all_to(settings, tmp_file.as_write())?;
temporary_files.push(tmp_file.finished_writing()?);
}
@ -379,7 +379,7 @@ fn check_child_success(mut child: Child, program: &str) -> UResult<()> {
pub trait WriteableTmpFile: Sized {
type Closed: ClosedTmpFile;
type InnerWrite: Write;
fn create(path: PathBuf, compress_prog: Option<&str>) -> UResult<Self>;
fn create(file: (File, PathBuf), compress_prog: Option<&str>) -> UResult<Self>;
/// Closes the temporary file.
fn finished_writing(self) -> UResult<Self::Closed>;
fn as_write(&mut self) -> &mut Self::InnerWrite;
@ -414,11 +414,9 @@ impl WriteableTmpFile for WriteablePlainTmpFile {
type Closed = ClosedPlainTmpFile;
type InnerWrite = BufWriter<File>;
fn create(path: PathBuf, _: Option<&str>) -> UResult<Self> {
fn create((file, path): (File, PathBuf), _: Option<&str>) -> UResult<Self> {
Ok(WriteablePlainTmpFile {
file: BufWriter::new(
File::create(&path).map_err(|error| SortError::OpenTmpFileFailed { error })?,
),
file: BufWriter::new(file),
path,
})
}
@ -476,12 +474,10 @@ impl WriteableTmpFile for WriteableCompressedTmpFile {
type Closed = ClosedCompressedTmpFile;
type InnerWrite = BufWriter<ChildStdin>;
fn create(path: PathBuf, compress_prog: Option<&str>) -> UResult<Self> {
fn create((file, path): (File, PathBuf), compress_prog: Option<&str>) -> UResult<Self> {
let compress_prog = compress_prog.unwrap();
let mut command = Command::new(compress_prog);
let tmp_file =
File::create(&path).map_err(|error| SortError::OpenTmpFileFailed { error })?;
command.stdin(Stdio::piped()).stdout(tmp_file);
command.stdin(Stdio::piped()).stdout(file);
let mut child = command
.spawn()
.map_err(|err| SortError::CompressProgExecutionFailed {

View file

@ -1,4 +1,5 @@
use std::{
fs::File,
path::{Path, PathBuf},
sync::{Arc, Mutex},
};
@ -54,7 +55,7 @@ impl TmpDirWrapper {
.map_err(|e| USimpleError::new(2, format!("failed to set up signal handler: {}", e)))
}
pub fn next_file_path(&mut self) -> UResult<PathBuf> {
pub fn next_file(&mut self) -> UResult<(File, PathBuf)> {
if self.temp_dir.is_none() {
self.init_tmp_dir()?;
}
@ -62,7 +63,11 @@ impl TmpDirWrapper {
let _lock = self.lock.lock().unwrap();
let file_name = self.size.to_string();
self.size += 1;
Ok(self.temp_dir.as_ref().unwrap().path().join(file_name))
let path = self.temp_dir.as_ref().unwrap().path().join(file_name);
Ok((
File::create(&path).map_err(|error| SortError::OpenTmpFileFailed { error })?,
path,
))
}
}