mkstemp/
lib.rs

1//! Safe wrapper over mkstemp function from libc
2//!
3//! Usage example:
4//!
5//! ```rust
6//! use std::io::Write;
7//! extern crate mkstemp;
8//! pub fn main() {
9//!     // delete automatically when it goes out of scope
10//!     let mut temp_file = mkstemp::TempFile::new("/tmp/testXXXXXX", true).unwrap();
11//!     temp_file.write("test content".as_bytes()).unwrap();
12//! }
13//! ```
14
15use std::io::{self, Read, Write};
16use std::fs::{File, remove_file};
17use std::os::unix::io::FromRawFd;
18use std::ffi::CString;
19use std::fmt::Arguments;
20
21extern crate libc;
22
23/// Temporary file
24pub struct TempFile {
25    // we use Option here as a trick to close the file in the drop trait
26    file: Option<File>,
27    path: String,
28    auto_delete: bool
29}
30
31impl TempFile {
32    /// Create temporary file
33    ///
34    /// * `template` - file template as described in mkstemp(3)<br/>
35    /// * `auto_delete` - if true the file will be automatically deleted when it goes out of scope<br/>
36    pub fn new(template: &str, auto_delete: bool) -> io::Result<TempFile> {
37        let ptr = CString::new(template)?.into_raw();
38        let fd = unsafe { libc::mkstemp(ptr) };
39        let path = unsafe { CString::from_raw(ptr) };
40
41        if fd < 0 {
42            return Err(io::Error::last_os_error())
43        }
44
45        let file = unsafe { File::from_raw_fd(fd) };
46
47        Ok(TempFile {
48            file: Some(file),
49            path: path.into_string().map_err(|e| io::Error::new(io::ErrorKind::Other, e))?,
50            auto_delete: auto_delete
51        })
52    }
53
54    /// Return a reference to the actual file path
55    pub fn path(&self) -> &str {
56        &self.path
57    }
58
59    /// Return a mutable reference to inner file
60    pub fn inner(&mut self) -> &mut File {
61        self.file.as_mut().unwrap()
62    }
63}
64
65impl Drop for TempFile {
66    fn drop(&mut self) {
67        // close the file
68        self.file = None;
69        if self.auto_delete {
70            let _ = remove_file(&self.path);
71        }
72    }
73}
74
75impl Read for TempFile {
76    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
77        self.inner().read(buf)
78    }
79
80    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
81        self.inner().read_to_end(buf)
82    }
83
84    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
85        self.inner().read_to_string(buf)
86    }
87
88    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
89        self.inner().read_exact(buf)
90    }
91}
92
93impl Write for TempFile {
94    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
95        self.inner().write(buf)
96    }
97
98    fn flush(&mut self) -> io::Result<()> {
99        self.inner().flush()
100    }
101
102    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
103        self.inner().write_all(buf)
104    }
105
106    fn write_fmt(&mut self, fmt: Arguments) -> io::Result<()> {
107        self.inner().write_fmt(fmt)
108    }
109}