1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
use std::path::Path;
use tempfile::{NamedTempFile, TempPath};
use crate::{handle, AutoRemove};
enum TempfileOrTemppath {
Tempfile(NamedTempFile),
Temppath(TempPath),
}
pub(crate) struct ForksafeTempfile {
inner: TempfileOrTemppath,
cleanup: AutoRemove,
pub owning_process_id: u32,
}
impl ForksafeTempfile {
pub fn new(tempfile: NamedTempFile, cleanup: AutoRemove, mode: handle::Mode) -> Self {
use handle::Mode::*;
ForksafeTempfile {
inner: match mode {
Closed => TempfileOrTemppath::Temppath(tempfile.into_temp_path()),
Writable => TempfileOrTemppath::Tempfile(tempfile),
},
cleanup,
owning_process_id: std::process::id(),
}
}
}
impl ForksafeTempfile {
pub fn as_mut_tempfile(&mut self) -> Option<&mut NamedTempFile> {
match &mut self.inner {
TempfileOrTemppath::Tempfile(file) => Some(file),
TempfileOrTemppath::Temppath(_) => None,
}
}
pub fn close(self) -> Self {
if let TempfileOrTemppath::Tempfile(file) = self.inner {
ForksafeTempfile {
inner: TempfileOrTemppath::Temppath(file.into_temp_path()),
cleanup: self.cleanup,
owning_process_id: self.owning_process_id,
}
} else {
self
}
}
pub fn persist(self, path: impl AsRef<Path>) -> Result<Option<std::fs::File>, (std::io::Error, Self)> {
self.persist_inner(path.as_ref())
}
fn persist_inner(mut self, path: &Path) -> Result<Option<std::fs::File>, (std::io::Error, Self)> {
match self.inner {
TempfileOrTemppath::Tempfile(file) => match file.persist(path) {
Ok(file) => Ok(Some(file)),
Err(err) => Err((err.error, {
self.inner = TempfileOrTemppath::Tempfile(err.file);
self
})),
},
TempfileOrTemppath::Temppath(temppath) => match temppath.persist(path) {
Ok(_) => Ok(None),
Err(err) => Err((err.error, {
self.inner = TempfileOrTemppath::Temppath(err.path);
self
})),
},
}
}
pub fn into_temppath(self) -> TempPath {
match self.inner {
TempfileOrTemppath::Tempfile(file) => file.into_temp_path(),
TempfileOrTemppath::Temppath(path) => path,
}
}
pub fn into_tempfile(self) -> Option<NamedTempFile> {
match self.inner {
TempfileOrTemppath::Tempfile(file) => Some(file),
TempfileOrTemppath::Temppath(_) => None,
}
}
pub fn drop_impl(self) {
let file_path = match self.inner {
TempfileOrTemppath::Tempfile(file) => file.path().to_owned(),
TempfileOrTemppath::Temppath(path) => path.to_path_buf(),
};
let parent_directory = file_path.parent().expect("every tempfile has a parent directory");
self.cleanup.execute_best_effort(parent_directory);
}
pub fn drop_without_deallocation(self) {
use std::io::Write;
let temppath = match self.inner {
TempfileOrTemppath::Tempfile(file) => {
let (mut file, temppath) = file.into_parts();
file.flush().ok();
temppath
}
TempfileOrTemppath::Temppath(path) => path,
};
std::fs::remove_file(&temppath).ok();
std::mem::forget(
self.cleanup
.execute_best_effort(temppath.parent().expect("every file has a directory")),
);
std::mem::forget(temppath); // leak memory to prevent deallocation
}
}
|