Skip to content

Commit

Permalink
[TempFile] Use mkstemp on linux
Browse files Browse the repository at this point in the history
This partially reverts commit 2e77de9,
as in that on unix we return to the behavior implemented before that
commit was made. By using mkstemp, we prevent potential filename
collisions from occuring (something firecracker occasionally observed
when running heavily parallelized testing workloads).

Code for the unix implementation is taken from the git history, with
minor adjustments to meet the now-higher linting bar.

On windows, we stick to the implementation of naming tempfiles after 6
random alphanumeric characters.

Signed-off-by: Patrick Roy <[email protected]>
  • Loading branch information
roypat committed Jan 10, 2023
1 parent c4e1221 commit 434c8d3
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 3 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
- [[#178](https://github.com/rust-vmm/vmm-sys-util/issues/178)]: Fixed a bug in
`rand_bytes` that was triggering a panic when the number of bytes was not a
multiple of 4.
- [[#181](https://github.com/rust-vmm/vmm-sys-util/pull/181)]: Changed
`TempFile::new_with_prefix()` on linux to use `mkstemp` to prevent name
collisions.

## v0.11.0

Expand Down
55 changes: 52 additions & 3 deletions src/tempfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@
use std::env::temp_dir;
use std::ffi::OsStr;
use std::fs;
use std::fs::{File, OpenOptions};
use std::fs::File;
use std::path::{Path, PathBuf};

use crate::errno::{Error, Result};
use crate::rand::rand_alphanumerics;
use libc;

use crate::errno::{errno_result, Error, Result};

/// Wrapper for working with temporary files.
///
Expand All @@ -51,7 +52,55 @@ impl TempFile {
/// `prefix`: The path and filename where to create the temporary file. Six
/// random alphanumeric characters will be added to the end of this to form
/// the filename.
#[cfg(unix)]
pub fn new_with_prefix<P: AsRef<OsStr>>(prefix: P) -> Result<TempFile> {
use std::ffi::CString;
use std::os::unix::{ffi::OsStrExt, io::FromRawFd};

let mut os_fname = prefix.as_ref().to_os_string();
os_fname.push("XXXXXX");

let raw_fname = match CString::new(os_fname.as_bytes()) {
Ok(c_string) => c_string.into_raw(),
Err(_) => return Err(Error::new(libc::EINVAL)),
};

// SAFETY: Safe because `raw_fname` originates from CString::into_raw, meaning
// it is a pointer to a nul-terminated sequence of characters.
let fd = unsafe { libc::mkstemp(raw_fname) };
if fd == -1 {
return errno_result();
}

// SAFETY: raw_fname originates from a call to CString::into_raw. The length
// of the string has not changed, as mkstemp returns a valid file name, and
// '\0' cannot be part of a valid filename.
let c_tempname = unsafe { CString::from_raw(raw_fname) };
let os_tempname = OsStr::from_bytes(c_tempname.as_bytes());

// SAFETY: Safe because we checked `fd != -1` above and we uniquely own the file
// descriptor. This `fd` will be freed etc when `File` and thus
// `TempFile` goes out of scope.
let file = unsafe { File::from_raw_fd(fd) };

Ok(TempFile {
path: PathBuf::from(os_tempname),
file: Some(file),
})
}

/// Creates the TempFile using a prefix.
///
/// # Arguments
///
/// `prefix`: The path and filename where to create the temporary file. Six
/// random alphanumeric characters will be added to the end of this to form
/// the filename.
#[cfg(windows)]
pub fn new_with_prefix<P: AsRef<OsStr>>(prefix: P) -> Result<TempFile> {
use crate::rand::rand_alphanumerics;
use std::fs::OpenOptions;

let file_path_str = format!(
"{}{}",
prefix.as_ref().to_str().unwrap_or_default(),
Expand Down

0 comments on commit 434c8d3

Please sign in to comment.