1use std::env;
2use std::ffi::CString;
3use std::fmt::Arguments;
4use std::fs::{self, File};
5use std::io::{Error, ErrorKind, Read, Result, Seek, SeekFrom, Write};
6
7#[cfg(unix)]
8use std::os::unix::io::FromRawFd;
9#[cfg(unix)]
10use libc::{c_int, mkstemps};
11
12pub struct TempFile {
14 file: Option<File>,
15 path: String,
16}
17
18impl TempFile {
19 pub fn new(prefix: &str, suffix: &str) -> Result<TempFile> {
38 debug!("init new TempFile");
39 let len = suffix.chars().count();
41 if len > std::i32::MAX as usize {
42 return Err(Error::new(
43 ErrorKind::InvalidData,
44 "Suffix length must be less than std::i32::MAX",
45 ));
46 }
47 debug!("validated suffix len");
48
49 let tmp_dir = env::temp_dir();
51 debug!("found temp dir: {:?}", tmp_dir);
52
53 let ptr = match CString::new(format!("{}/{}XXXXXX{}", tmp_dir.display(), prefix, suffix)) {
55 Ok(p) => p.into_raw(),
56 Err(e) => return Err(Error::new(ErrorKind::Other, e)),
57 };
58 debug!("CString to raw done");
59
60 let fd = unsafe { mkstemps(ptr, len as c_int) };
62 debug!("got fd: {}", fd);
63
64 let path = match unsafe { CString::from_raw(ptr) }.into_string() {
66 Ok(s) => s,
67 Err(e) => return Err(Error::new(ErrorKind::Other, e)),
68 };
69 debug!("raw to CString to String done");
70 debug!("got file path: {}", &path);
71
72 if fd < 0 {
74 debug!("fd was error");
75 return Err(Error::last_os_error());
76 }
77
78 let file = unsafe { File::from_raw_fd(fd) };
80 debug!("got file from fd");
81
82 Ok(TempFile {
84 file: Some(file),
85 path: path,
86 })
87 }
88
89 pub fn path(&self) -> &str {
91 &self.path
92 }
93
94 pub fn inner(&mut self) -> &mut File {
96 self.file.as_mut().unwrap()
97 }
98}
99
100impl Drop for TempFile {
101 fn drop(&mut self) {
102 debug!("Dropping TempFile: {}", &self.path);
103 self.file = None;
104 let _ = fs::remove_file(&self.path);
105 }
106}
107
108impl Seek for TempFile {
109 fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
110 self.inner().seek(pos)
111 }
112}
113
114impl Read for TempFile {
115 fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
116 self.inner().read(buf)
117 }
118
119 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
120 self.inner().read_to_end(buf)
121 }
122
123 fn read_to_string(&mut self, buf: &mut String) -> Result<usize> {
124 self.inner().read_to_string(buf)
125 }
126
127 fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
128 self.inner().read_exact(buf)
129 }
130}
131
132impl Write for TempFile {
133 fn write(&mut self, buf: &[u8]) -> Result<usize> {
134 self.inner().write(buf)
135 }
136
137 fn flush(&mut self) -> Result<()> {
138 self.inner().flush()
139 }
140
141 fn write_all(&mut self, buf: &[u8]) -> Result<()> {
142 self.inner().write_all(buf)
143 }
144
145 fn write_fmt(&mut self, fmt: Arguments<'_>) -> Result<()> {
146 self.inner().write_fmt(fmt)
147 }
148}