summaryrefslogtreecommitdiffstats
path: root/vendor/tempfile/src
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/tempfile/src')
-rw-r--r--vendor/tempfile/src/dir.rs31
-rw-r--r--vendor/tempfile/src/file/imp/mod.rs4
-rw-r--r--vendor/tempfile/src/file/imp/unix.rs41
-rw-r--r--vendor/tempfile/src/file/mod.rs30
-rw-r--r--vendor/tempfile/src/lib.rs41
-rw-r--r--vendor/tempfile/src/spooled.rs42
-rw-r--r--vendor/tempfile/src/util.rs17
7 files changed, 142 insertions, 64 deletions
diff --git a/vendor/tempfile/src/dir.rs b/vendor/tempfile/src/dir.rs
index d6307627f..d5a944b6f 100644
--- a/vendor/tempfile/src/dir.rs
+++ b/vendor/tempfile/src/dir.rs
@@ -9,6 +9,7 @@
// except according to those terms.
use remove_dir_all::remove_dir_all;
+use std::mem;
use std::path::{self, Path, PathBuf};
use std::{fmt, fs, io};
@@ -192,7 +193,7 @@ pub fn tempdir_in<P: AsRef<Path>>(dir: P) -> io::Result<TempDir> {
/// [`std::fs`]: http://doc.rust-lang.org/std/fs/index.html
/// [`std::process::exit()`]: http://doc.rust-lang.org/std/process/fn.exit.html
pub struct TempDir {
- path: Option<PathBuf>,
+ path: Box<Path>,
}
impl TempDir {
@@ -292,7 +293,7 @@ impl TempDir {
/// # }
/// ```
pub fn path(&self) -> &path::Path {
- self.path.as_ref().unwrap()
+ self.path.as_ref()
}
/// Persist the temporary directory to disk, returning the [`PathBuf`] where it is located.
@@ -322,8 +323,13 @@ impl TempDir {
/// # Ok(())
/// # }
/// ```
- pub fn into_path(mut self) -> PathBuf {
- self.path.take().unwrap()
+ pub fn into_path(self) -> PathBuf {
+ // Prevent the Drop impl from being called.
+ let mut this = mem::ManuallyDrop::new(self);
+
+ // replace this.path with an empty Box, since an empty Box does not
+ // allocate any heap memory.
+ mem::replace(&mut this.path, PathBuf::new().into_boxed_path()).into()
}
/// Closes and removes the temporary directory, returning a `Result`.
@@ -369,8 +375,12 @@ impl TempDir {
pub fn close(mut self) -> io::Result<()> {
let result = remove_dir_all(self.path()).with_err_path(|| self.path());
- // Prevent the Drop impl from removing the dir a second time.
- self.path = None;
+ // Set self.path to empty Box to release the memory, since an empty
+ // Box does not allocate any heap memory.
+ self.path = PathBuf::new().into_boxed_path();
+
+ // Prevent the Drop impl from being called.
+ mem::forget(self);
result
}
@@ -392,15 +402,14 @@ impl fmt::Debug for TempDir {
impl Drop for TempDir {
fn drop(&mut self) {
- // Path is `None` if `close()` or `into_path()` has been called.
- if let Some(ref p) = self.path {
- let _ = remove_dir_all(p);
- }
+ let _ = remove_dir_all(self.path());
}
}
pub(crate) fn create(path: PathBuf) -> io::Result<TempDir> {
fs::create_dir(&path)
.with_err_path(|| &path)
- .map(|_| TempDir { path: Some(path) })
+ .map(|_| TempDir {
+ path: path.into_boxed_path(),
+ })
}
diff --git a/vendor/tempfile/src/file/imp/mod.rs b/vendor/tempfile/src/file/imp/mod.rs
index 31e872886..fbb2bbf63 100644
--- a/vendor/tempfile/src/file/imp/mod.rs
+++ b/vendor/tempfile/src/file/imp/mod.rs
@@ -1,5 +1,5 @@
-cfg_if! {
- if #[cfg(any(unix, target_os = "redox"))] {
+cfg_if::cfg_if! {
+ if #[cfg(any(unix, target_os = "redox", target_os = "wasi"))] {
mod unix;
pub use self::unix::*;
} else if #[cfg(windows)] {
diff --git a/vendor/tempfile/src/file/imp/unix.rs b/vendor/tempfile/src/file/imp/unix.rs
index 35b1ddb1e..480743cf7 100644
--- a/vendor/tempfile/src/file/imp/unix.rs
+++ b/vendor/tempfile/src/file/imp/unix.rs
@@ -2,10 +2,18 @@ use std::env;
use std::ffi::{CString, OsStr};
use std::fs::{self, File, OpenOptions};
use std::io;
-use std::os::unix::ffi::OsStrExt;
-use std::os::unix::fs::{MetadataExt, OpenOptionsExt};
-use std::path::Path;
+cfg_if::cfg_if! {
+ if #[cfg(not(target_os = "wasi"))] {
+ use std::os::unix::ffi::OsStrExt;
+ use std::os::unix::fs::{MetadataExt, OpenOptionsExt};
+ } else {
+ use std::os::wasi::ffi::OsStrExt;
+ #[cfg(feature = "nightly")]
+ use std::os::wasi::fs::MetadataExt;
+ }
+}
use crate::util;
+use std::path::Path;
#[cfg(not(target_os = "redox"))]
use libc::{c_char, c_int, link, rename, unlink};
@@ -33,12 +41,14 @@ pub fn cstr(path: &Path) -> io::Result<CString> {
}
pub fn create_named(path: &Path, open_options: &mut OpenOptions) -> io::Result<File> {
- open_options
- .read(true)
- .write(true)
- .create_new(true)
- .mode(0o600)
- .open(path)
+ open_options.read(true).write(true).create_new(true);
+
+ #[cfg(not(target_os = "wasi"))]
+ {
+ open_options.mode(0o600);
+ }
+
+ open_options.open(path)
}
fn create_unlinked(path: &Path) -> io::Result<File> {
@@ -60,11 +70,11 @@ fn create_unlinked(path: &Path) -> io::Result<File> {
#[cfg(target_os = "linux")]
pub fn create(dir: &Path) -> io::Result<File> {
- use libc::{EISDIR, ENOENT, EOPNOTSUPP, O_EXCL, O_TMPFILE};
+ use libc::{EISDIR, ENOENT, EOPNOTSUPP, O_TMPFILE};
OpenOptions::new()
.read(true)
.write(true)
- .custom_flags(O_TMPFILE | O_EXCL) // do not mix with `create_new(true)`
+ .custom_flags(O_TMPFILE) // do not mix with `create_new(true)`
.open(dir)
.or_else(|e| {
match e.raw_os_error() {
@@ -90,6 +100,7 @@ fn create_unix(dir: &Path) -> io::Result<File> {
)
}
+#[cfg(any(not(target_os = "wasi"), feature = "nightly"))]
pub fn reopen(file: &File, path: &Path) -> io::Result<File> {
let new_file = OpenOptions::new().read(true).write(true).open(path)?;
let old_meta = file.metadata()?;
@@ -103,6 +114,14 @@ pub fn reopen(file: &File, path: &Path) -> io::Result<File> {
Ok(new_file)
}
+#[cfg(all(target_os = "wasi", not(feature = "nightly")))]
+pub fn reopen(_file: &File, _path: &Path) -> io::Result<File> {
+ return Err(io::Error::new(
+ io::ErrorKind::Other,
+ "this operation is supported on WASI only on nightly Rust (with `nightly` feature enabled)",
+ ));
+}
+
#[cfg(not(target_os = "redox"))]
pub fn persist(old_path: &Path, new_path: &Path, overwrite: bool) -> io::Result<()> {
unsafe {
diff --git a/vendor/tempfile/src/file/mod.rs b/vendor/tempfile/src/file/mod.rs
index 31fdd4bed..b859ced79 100644
--- a/vendor/tempfile/src/file/mod.rs
+++ b/vendor/tempfile/src/file/mod.rs
@@ -138,7 +138,7 @@ impl error::Error for PathPersistError {
///
/// When dropped, the temporary file is deleted.
pub struct TempPath {
- path: PathBuf,
+ path: Box<Path>,
}
impl TempPath {
@@ -176,8 +176,8 @@ impl TempPath {
/// # }
/// ```
pub fn close(mut self) -> io::Result<()> {
- let result = fs::remove_file(&self.path).with_err_path(|| &self.path);
- self.path = PathBuf::new();
+ let result = fs::remove_file(&self.path).with_err_path(|| &*self.path);
+ self.path = PathBuf::new().into_boxed_path();
mem::forget(self);
result
}
@@ -231,7 +231,7 @@ impl TempPath {
// Don't drop `self`. We don't want to try deleting the old
// temporary file path. (It'll fail, but the failure is never
// seen.)
- self.path = PathBuf::new();
+ self.path = PathBuf::new().into_boxed_path();
mem::forget(self);
Ok(())
}
@@ -293,7 +293,7 @@ impl TempPath {
// Don't drop `self`. We don't want to try deleting the old
// temporary file path. (It'll fail, but the failure is never
// seen.)
- self.path = PathBuf::new();
+ self.path = PathBuf::new().into_boxed_path();
mem::forget(self);
Ok(())
}
@@ -341,9 +341,9 @@ impl TempPath {
// Don't drop `self`. We don't want to try deleting the old
// temporary file path. (It'll fail, but the failure is never
// seen.)
- let path = mem::replace(&mut self.path, PathBuf::new());
+ let path = mem::replace(&mut self.path, PathBuf::new().into_boxed_path());
mem::forget(self);
- Ok(path)
+ Ok(path.into())
}
Err(e) => Err(PathPersistError {
error: e,
@@ -351,6 +351,18 @@ impl TempPath {
}),
}
}
+
+ /// Create a new TempPath from an existing path. This can be done even if no
+ /// file exists at the given path.
+ ///
+ /// This is mostly useful for interacting with libraries and external
+ /// components that provide files to be consumed or expect a path with no
+ /// existing file to be given.
+ pub fn from_path(path: impl Into<PathBuf>) -> Self {
+ Self {
+ path: path.into().into_boxed_path(),
+ }
+ }
}
impl fmt::Debug for TempPath {
@@ -953,7 +965,9 @@ pub(crate) fn create_named(
imp::create_named(&path, open_options)
.with_err_path(|| path.clone())
.map(|file| NamedTempFile {
- path: TempPath { path },
+ path: TempPath {
+ path: path.into_boxed_path(),
+ },
file,
})
}
diff --git a/vendor/tempfile/src/lib.rs b/vendor/tempfile/src/lib.rs
index 51c2da09a..c38ca7b87 100644
--- a/vendor/tempfile/src/lib.rs
+++ b/vendor/tempfile/src/lib.rs
@@ -27,6 +27,42 @@
//! rely on file paths for _some_ operations. See the security documentation on
//! the `NamedTempFile` type for more information.
//!
+//! ## Early drop pitfall
+//!
+//! Because `TempDir` and `NamedTempFile` rely on their destructors for cleanup, this can lead
+//! to an unexpected early removal of the directory/file, usually when working with APIs which are
+//! generic over `AsRef<Path>`. Consider the following example:
+//!
+//! ```no_run
+//! # use tempfile::tempdir;
+//! # use std::io;
+//! # use std::process::Command;
+//! # fn main() {
+//! # if let Err(_) = run() {
+//! # ::std::process::exit(1);
+//! # }
+//! # }
+//! # fn run() -> Result<(), io::Error> {
+//! // Create a directory inside of `std::env::temp_dir()`.
+//! let temp_dir = tempdir()?;
+//!
+//! // Spawn the `touch` command inside the temporary directory and collect the exit status
+//! // Note that `temp_dir` is **not** moved into `current_dir`, but passed as a reference
+//! let exit_status = Command::new("touch").arg("tmp").current_dir(&temp_dir).status()?;
+//! assert!(exit_status.success());
+//!
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! This works because a reference to `temp_dir` is passed to `current_dir`, resulting in the
+//! destructor of `temp_dir` being run after the `Command` has finished execution. Moving the
+//! `TempDir` into the `current_dir` call would result in the `TempDir` being converted into
+//! an internal representation, with the original value being dropped and the directory thus
+//! being deleted, before the command can be executed.
+//!
+//! The `touch` command would fail with an `No such file or directory` error.
+//!
//! ## Examples
//!
//! Create a temporary file and write some data into it:
@@ -125,9 +161,10 @@
#![cfg_attr(test, deny(warnings))]
#![deny(rust_2018_idioms)]
#![allow(clippy::redundant_field_names)]
+#![cfg_attr(feature = "nightly", feature(wasi_ext))]
-#[macro_use]
-extern crate cfg_if;
+#[cfg(doctest)]
+doc_comment::doctest!("../README.md");
const NUM_RETRIES: u32 = 1 << 31;
const NUM_RAND_CHARS: usize = 6;
diff --git a/vendor/tempfile/src/spooled.rs b/vendor/tempfile/src/spooled.rs
index e6f750e58..ed6c16fb4 100644
--- a/vendor/tempfile/src/spooled.rs
+++ b/vendor/tempfile/src/spooled.rs
@@ -2,8 +2,9 @@ use crate::file::tempfile;
use std::fs::File;
use std::io::{self, Cursor, Read, Seek, SeekFrom, Write};
+/// A wrapper for the two states of a `SpooledTempFile`.
#[derive(Debug)]
-enum SpooledInner {
+pub enum SpooledData {
InMemory(Cursor<Vec<u8>>),
OnDisk(File),
}
@@ -15,7 +16,7 @@ enum SpooledInner {
#[derive(Debug)]
pub struct SpooledTempFile {
max_size: usize,
- inner: SpooledInner,
+ inner: SpooledData,
}
/// Create a new spooled temporary file.
@@ -66,15 +67,15 @@ impl SpooledTempFile {
pub fn new(max_size: usize) -> SpooledTempFile {
SpooledTempFile {
max_size: max_size,
- inner: SpooledInner::InMemory(Cursor::new(Vec::new())),
+ inner: SpooledData::InMemory(Cursor::new(Vec::new())),
}
}
/// Returns true if the file has been rolled over to disk.
pub fn is_rolled(&self) -> bool {
match self.inner {
- SpooledInner::InMemory(_) => false,
- SpooledInner::OnDisk(_) => true,
+ SpooledData::InMemory(_) => false,
+ SpooledData::OnDisk(_) => true,
}
}
@@ -83,11 +84,11 @@ impl SpooledTempFile {
pub fn roll(&mut self) -> io::Result<()> {
if !self.is_rolled() {
let mut file = tempfile()?;
- if let SpooledInner::InMemory(ref mut cursor) = self.inner {
+ if let SpooledData::InMemory(ref mut cursor) = self.inner {
file.write_all(cursor.get_ref())?;
file.seek(SeekFrom::Start(cursor.position()))?;
}
- self.inner = SpooledInner::OnDisk(file);
+ self.inner = SpooledData::OnDisk(file);
}
Ok(())
}
@@ -97,20 +98,25 @@ impl SpooledTempFile {
self.roll()?; // does nothing if already rolled over
}
match self.inner {
- SpooledInner::InMemory(ref mut cursor) => {
+ SpooledData::InMemory(ref mut cursor) => {
cursor.get_mut().resize(size as usize, 0);
Ok(())
}
- SpooledInner::OnDisk(ref mut file) => file.set_len(size),
+ SpooledData::OnDisk(ref mut file) => file.set_len(size),
}
}
+
+ /// Consumes and returns the inner `SpooledData` type.
+ pub fn into_inner(self) -> SpooledData {
+ self.inner
+ }
}
impl Read for SpooledTempFile {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self.inner {
- SpooledInner::InMemory(ref mut cursor) => cursor.read(buf),
- SpooledInner::OnDisk(ref mut file) => file.read(buf),
+ SpooledData::InMemory(ref mut cursor) => cursor.read(buf),
+ SpooledData::OnDisk(ref mut file) => file.read(buf),
}
}
}
@@ -119,7 +125,7 @@ impl Write for SpooledTempFile {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
// roll over to file if necessary
let mut rolling = false;
- if let SpooledInner::InMemory(ref mut cursor) = self.inner {
+ if let SpooledData::InMemory(ref mut cursor) = self.inner {
rolling = cursor.position() as usize + buf.len() > self.max_size;
}
if rolling {
@@ -128,16 +134,16 @@ impl Write for SpooledTempFile {
// write the bytes
match self.inner {
- SpooledInner::InMemory(ref mut cursor) => cursor.write(buf),
- SpooledInner::OnDisk(ref mut file) => file.write(buf),
+ SpooledData::InMemory(ref mut cursor) => cursor.write(buf),
+ SpooledData::OnDisk(ref mut file) => file.write(buf),
}
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
match self.inner {
- SpooledInner::InMemory(ref mut cursor) => cursor.flush(),
- SpooledInner::OnDisk(ref mut file) => file.flush(),
+ SpooledData::InMemory(ref mut cursor) => cursor.flush(),
+ SpooledData::OnDisk(ref mut file) => file.flush(),
}
}
}
@@ -145,8 +151,8 @@ impl Write for SpooledTempFile {
impl Seek for SpooledTempFile {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
match self.inner {
- SpooledInner::InMemory(ref mut cursor) => cursor.seek(pos),
- SpooledInner::OnDisk(ref mut file) => file.seek(pos),
+ SpooledData::InMemory(ref mut cursor) => cursor.seek(pos),
+ SpooledData::OnDisk(ref mut file) => file.seek(pos),
}
}
}
diff --git a/vendor/tempfile/src/util.rs b/vendor/tempfile/src/util.rs
index aa76bb256..8c91b9c69 100644
--- a/vendor/tempfile/src/util.rs
+++ b/vendor/tempfile/src/util.rs
@@ -1,23 +1,16 @@
-use rand::distributions::Alphanumeric;
-use rand::{self, Rng};
+use fastrand;
use std::ffi::{OsStr, OsString};
use std::path::{Path, PathBuf};
-use std::{io, str};
+use std::{io, iter::repeat_with};
use crate::error::IoResultExt;
fn tmpname(prefix: &OsStr, suffix: &OsStr, rand_len: usize) -> OsString {
let mut buf = OsString::with_capacity(prefix.len() + suffix.len() + rand_len);
buf.push(prefix);
-
- // Push each character in one-by-one. Unfortunately, this is the only
- // safe(ish) simple way to do this without allocating a temporary
- // String/Vec.
- unsafe {
- rand::thread_rng()
- .sample_iter(&Alphanumeric)
- .take(rand_len)
- .for_each(|b| buf.push(str::from_utf8_unchecked(&[b as u8])))
+ let mut char_buf = [0u8; 4];
+ for c in repeat_with(fastrand::alphanumeric).take(rand_len) {
+ buf.push(c.encode_utf8(&mut char_buf));
}
buf.push(suffix);
buf