diff options
Diffstat (limited to 'vendor/tempfile/src/file')
-rw-r--r-- | vendor/tempfile/src/file/imp/other.rs | 4 | ||||
-rw-r--r-- | vendor/tempfile/src/file/imp/unix.rs | 85 | ||||
-rw-r--r-- | vendor/tempfile/src/file/imp/windows.rs | 13 | ||||
-rw-r--r-- | vendor/tempfile/src/file/mod.rs | 151 |
4 files changed, 133 insertions, 120 deletions
diff --git a/vendor/tempfile/src/file/imp/other.rs b/vendor/tempfile/src/file/imp/other.rs index d8a55a745..8721d2da6 100644 --- a/vendor/tempfile/src/file/imp/other.rs +++ b/vendor/tempfile/src/file/imp/other.rs @@ -9,7 +9,7 @@ fn not_supported<T>() -> io::Result<T> { )) } -pub fn create_named(_path: &Path, open_options: &mut OpenOptions) -> io::Result<File> { +pub fn create_named(_path: &Path, _open_options: &mut OpenOptions) -> io::Result<File> { not_supported() } @@ -25,6 +25,6 @@ pub fn persist(_old_path: &Path, _new_path: &Path, _overwrite: bool) -> io::Resu not_supported() } -pub fn keep(path: &Path) -> io::Result<()> { +pub fn keep(_path: &Path) -> io::Result<()> { not_supported() } diff --git a/vendor/tempfile/src/file/imp/unix.rs b/vendor/tempfile/src/file/imp/unix.rs index 480743cf7..c305ea95e 100644 --- a/vendor/tempfile/src/file/imp/unix.rs +++ b/vendor/tempfile/src/file/imp/unix.rs @@ -1,13 +1,11 @@ use std::env; -use std::ffi::{CString, OsStr}; +use std::ffi::OsStr; use std::fs::{self, File, OpenOptions}; use std::io; 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; } @@ -16,29 +14,7 @@ use crate::util; use std::path::Path; #[cfg(not(target_os = "redox"))] -use libc::{c_char, c_int, link, rename, unlink}; - -#[cfg(not(target_os = "redox"))] -#[inline(always)] -pub fn cvt_err(result: c_int) -> io::Result<c_int> { - if result == -1 { - Err(io::Error::last_os_error()) - } else { - Ok(result) - } -} - -#[cfg(target_os = "redox")] -#[inline(always)] -pub fn cvt_err(result: Result<usize, syscall::Error>) -> io::Result<usize> { - result.map_err(|err| io::Error::from_raw_os_error(err.errno)) -} - -// Stolen from std. -pub fn cstr(path: &Path) -> io::Result<CString> { - CString::new(path.as_os_str().as_bytes()) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "path contained a null")) -} +use rustix::fs::{cwd, linkat, renameat, unlinkat, AtFlags}; pub fn create_named(path: &Path, open_options: &mut OpenOptions) -> io::Result<File> { open_options.read(true).write(true).create_new(true); @@ -70,16 +46,18 @@ 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_TMPFILE}; + use rustix::{fs::OFlags, io::Errno}; OpenOptions::new() .read(true) .write(true) - .custom_flags(O_TMPFILE) // do not mix with `create_new(true)` + .custom_flags(OFlags::TMPFILE.bits() as i32) // do not mix with `create_new(true)` .open(dir) .or_else(|e| { - match e.raw_os_error() { + match Errno::from_io_error(&e) { // These are the three "not supported" error codes for O_TMPFILE. - Some(EOPNOTSUPP) | Some(EISDIR) | Some(ENOENT) => create_unix(dir), + Some(Errno::OPNOTSUPP) | Some(Errno::ISDIR) | Some(Errno::NOENT) => { + create_unix(dir) + } _ => Err(e), } }) @@ -124,29 +102,40 @@ pub fn reopen(_file: &File, _path: &Path) -> io::Result<File> { #[cfg(not(target_os = "redox"))] pub fn persist(old_path: &Path, new_path: &Path, overwrite: bool) -> io::Result<()> { - unsafe { - let old_path = cstr(old_path)?; - let new_path = cstr(new_path)?; - if overwrite { - cvt_err(rename( - old_path.as_ptr() as *const c_char, - new_path.as_ptr() as *const c_char, - ))?; - } else { - cvt_err(link( - old_path.as_ptr() as *const c_char, - new_path.as_ptr() as *const c_char, - ))?; - // Ignore unlink errors. Can we do better? - // On recent linux, we can use renameat2 to do this atomically. - let _ = unlink(old_path.as_ptr() as *const c_char); + if overwrite { + renameat(cwd(), old_path, cwd(), new_path)?; + } else { + // On Linux, use `renameat_with` to avoid overwriting an existing name, + // if the kernel and the filesystem support it. + #[cfg(any(target_os = "android", target_os = "linux"))] + { + use rustix::fs::{renameat_with, RenameFlags}; + use rustix::io::Errno; + use std::sync::atomic::{AtomicBool, Ordering::Relaxed}; + + static NOSYS: AtomicBool = AtomicBool::new(false); + if !NOSYS.load(Relaxed) { + match renameat_with(cwd(), old_path, cwd(), new_path, RenameFlags::NOREPLACE) { + Ok(()) => return Ok(()), + Err(Errno::NOSYS) => NOSYS.store(true, Relaxed), + Err(Errno::INVAL) => {} + Err(e) => return Err(e.into()), + } + } } - Ok(()) + + // Otherwise use `linkat` to create the new filesystem name, which + // will fail if the name already exists, and then `unlinkat` to remove + // the old name. + linkat(cwd(), old_path, cwd(), new_path, AtFlags::empty())?; + // Ignore unlink errors. Can we do better? + let _ = unlinkat(cwd(), old_path, AtFlags::empty()); } + Ok(()) } #[cfg(target_os = "redox")] -pub fn persist(old_path: &Path, new_path: &Path, overwrite: bool) -> io::Result<()> { +pub fn persist(_old_path: &Path, _new_path: &Path, _overwrite: bool) -> io::Result<()> { // XXX implement when possible Err(io::Error::from_raw_os_error(syscall::ENOSYS)) } diff --git a/vendor/tempfile/src/file/imp/windows.rs b/vendor/tempfile/src/file/imp/windows.rs index 71b474880..cb2673b5a 100644 --- a/vendor/tempfile/src/file/imp/windows.rs +++ b/vendor/tempfile/src/file/imp/windows.rs @@ -6,13 +6,12 @@ use std::os::windows::io::{AsRawHandle, FromRawHandle, RawHandle}; use std::path::Path; use std::{io, iter}; -use winapi::um::fileapi::SetFileAttributesW; -use winapi::um::handleapi::INVALID_HANDLE_VALUE; -use winapi::um::winbase::{MoveFileExW, ReOpenFile}; -use winapi::um::winbase::{FILE_FLAG_DELETE_ON_CLOSE, MOVEFILE_REPLACE_EXISTING}; -use winapi::um::winnt::{FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_TEMPORARY}; -use winapi::um::winnt::{FILE_GENERIC_READ, FILE_GENERIC_WRITE, HANDLE}; -use winapi::um::winnt::{FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE}; +use windows_sys::Win32::Foundation::{HANDLE, INVALID_HANDLE_VALUE}; +use windows_sys::Win32::Storage::FileSystem::{ + MoveFileExW, ReOpenFile, SetFileAttributesW, FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_TEMPORARY, + FILE_FLAG_DELETE_ON_CLOSE, FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_SHARE_DELETE, + FILE_SHARE_READ, FILE_SHARE_WRITE, MOVEFILE_REPLACE_EXISTING, +}; use crate::util; diff --git a/vendor/tempfile/src/file/mod.rs b/vendor/tempfile/src/file/mod.rs index b859ced79..023acd26a 100644 --- a/vendor/tempfile/src/file/mod.rs +++ b/vendor/tempfile/src/file/mod.rs @@ -52,7 +52,7 @@ mod imp; /// /// [`std::env::temp_dir()`]: https://doc.rust-lang.org/std/env/fn.temp_dir.html pub fn tempfile() -> io::Result<File> { - tempfile_in(&env::temp_dir()) + tempfile_in(env::temp_dir()) } /// Create a new temporary file in the specified directory. @@ -467,29 +467,31 @@ impl AsRef<OsStr> for TempPath { /// # Resource Leaking /// /// If the program exits before the `NamedTempFile` destructor is -/// run, such as via [`std::process::exit()`], by segfaulting, or by -/// receiving a signal like `SIGINT`, then the temporary file -/// will not be deleted. +/// run, the temporary file will not be deleted. This can happen +/// if the process exits using [`std::process::exit()`], a segfault occurs, +/// receiving an interrupt signal like `SIGINT` that is not handled, or by using +/// a statically declared `NamedTempFile` instance (like with [`lazy_static`]). /// -/// Use the [`tempfile()`] function unless you absolutely need a named file. +/// Use the [`tempfile()`] function unless you need a named file path. /// /// [`tempfile()`]: fn.tempfile.html /// [`NamedTempFile::new()`]: #method.new /// [`NamedTempFile::new_in()`]: #method.new_in /// [`std::env::temp_dir()`]: https://doc.rust-lang.org/std/env/fn.temp_dir.html /// [`std::process::exit()`]: http://doc.rust-lang.org/std/process/fn.exit.html -pub struct NamedTempFile { +/// [`lazy_static`]: https://github.com/rust-lang-nursery/lazy-static.rs/issues/62 +pub struct NamedTempFile<F = File> { path: TempPath, - file: File, + file: F, } -impl fmt::Debug for NamedTempFile { +impl<F> fmt::Debug for NamedTempFile<F> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "NamedTempFile({:?})", self.path) } } -impl AsRef<Path> for NamedTempFile { +impl<F> AsRef<Path> for NamedTempFile<F> { #[inline] fn as_ref(&self) -> &Path { self.path() @@ -497,41 +499,46 @@ impl AsRef<Path> for NamedTempFile { } /// Error returned when persisting a temporary file fails. -#[derive(Debug)] -pub struct PersistError { +pub struct PersistError<F = File> { /// The underlying IO error. pub error: io::Error, /// The temporary file that couldn't be persisted. - pub file: NamedTempFile, + pub file: NamedTempFile<F>, +} + +impl<F> fmt::Debug for PersistError<F> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "PersistError({:?})", self.error) + } } -impl From<PersistError> for io::Error { +impl<F> From<PersistError<F>> for io::Error { #[inline] - fn from(error: PersistError) -> io::Error { + fn from(error: PersistError<F>) -> io::Error { error.error } } -impl From<PersistError> for NamedTempFile { +impl<F> From<PersistError<F>> for NamedTempFile<F> { #[inline] - fn from(error: PersistError) -> NamedTempFile { + fn from(error: PersistError<F>) -> NamedTempFile<F> { error.file } } -impl fmt::Display for PersistError { +impl<F> fmt::Display for PersistError<F> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "failed to persist temporary file: {}", self.error) } } -impl error::Error for PersistError { +impl<F> error::Error for PersistError<F> { fn source(&self) -> Option<&(dyn error::Error + 'static)> { Some(&self.error) } } -impl NamedTempFile { +impl NamedTempFile<File> { /// Create a new named temporary file. /// /// See [`Builder`] for more configuration. @@ -601,7 +608,9 @@ impl NamedTempFile { pub fn new_in<P: AsRef<Path>>(dir: P) -> io::Result<NamedTempFile> { Builder::new().tempfile_in(dir) } +} +impl<F> NamedTempFile<F> { /// Get the temporary file's path. /// /// # Security @@ -711,7 +720,7 @@ impl NamedTempFile { /// ``` /// /// [`PersistError`]: struct.PersistError.html - pub fn persist<P: AsRef<Path>>(self, new_path: P) -> Result<File, PersistError> { + pub fn persist<P: AsRef<Path>>(self, new_path: P) -> Result<F, PersistError<F>> { let NamedTempFile { path, file } = self; match path.persist(new_path) { Ok(_) => Ok(file), @@ -764,7 +773,7 @@ impl NamedTempFile { /// # Ok(()) /// # } /// ``` - pub fn persist_noclobber<P: AsRef<Path>>(self, new_path: P) -> Result<File, PersistError> { + pub fn persist_noclobber<P: AsRef<Path>>(self, new_path: P) -> Result<F, PersistError<F>> { let NamedTempFile { path, file } = self; match path.persist_noclobber(new_path) { Ok(_) => Ok(file), @@ -808,7 +817,7 @@ impl NamedTempFile { /// ``` /// /// [`PathPersistError`]: struct.PathPersistError.html - pub fn keep(self) -> Result<(File, PathBuf), PersistError> { + pub fn keep(self) -> Result<(F, PathBuf), PersistError<F>> { let (file, path) = (self.file, self.path); match path.keep() { Ok(path) => Ok((file, path)), @@ -819,6 +828,49 @@ impl NamedTempFile { } } + /// Get a reference to the underlying file. + pub fn as_file(&self) -> &F { + &self.file + } + + /// Get a mutable reference to the underlying file. + pub fn as_file_mut(&mut self) -> &mut F { + &mut self.file + } + + /// Convert the temporary file into a `std::fs::File`. + /// + /// The inner file will be deleted. + pub fn into_file(self) -> F { + self.file + } + + /// Closes the file, leaving only the temporary file path. + /// + /// This is useful when another process must be able to open the temporary + /// file. + pub fn into_temp_path(self) -> TempPath { + self.path + } + + /// Converts the named temporary file into its constituent parts. + /// + /// Note: When the path is dropped, the file is deleted but the file handle + /// is still usable. + pub fn into_parts(self) -> (F, TempPath) { + (self.file, self.path) + } + + /// Creates a `NamedTempFile` from its constituent parts. + /// + /// This can be used with [`NamedTempFile::into_parts`] to reconstruct the + /// `NamedTempFile`. + pub fn from_parts(file: F, path: TempPath) -> Self { + Self { file, path } + } +} + +impl NamedTempFile<File> { /// Securely reopen the temporary file. /// /// This function is useful when you need multiple independent handles to @@ -858,54 +910,21 @@ impl NamedTempFile { imp::reopen(self.as_file(), NamedTempFile::path(self)) .with_err_path(|| NamedTempFile::path(self)) } - - /// Get a reference to the underlying file. - pub fn as_file(&self) -> &File { - &self.file - } - - /// Get a mutable reference to the underlying file. - pub fn as_file_mut(&mut self) -> &mut File { - &mut self.file - } - - /// Convert the temporary file into a `std::fs::File`. - /// - /// The inner file will be deleted. - pub fn into_file(self) -> File { - self.file - } - - /// Closes the file, leaving only the temporary file path. - /// - /// This is useful when another process must be able to open the temporary - /// file. - pub fn into_temp_path(self) -> TempPath { - self.path - } - - /// Converts the named temporary file into its constituent parts. - /// - /// Note: When the path is dropped, the file is deleted but the file handle - /// is still usable. - pub fn into_parts(self) -> (File, TempPath) { - (self.file, self.path) - } } -impl Read for NamedTempFile { +impl<F: Read> Read for NamedTempFile<F> { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.as_file_mut().read(buf).with_err_path(|| self.path()) } } -impl<'a> Read for &'a NamedTempFile { +impl Read for &NamedTempFile<File> { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.as_file().read(buf).with_err_path(|| self.path()) } } -impl Write for NamedTempFile { +impl<F: Write> Write for NamedTempFile<F> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.as_file_mut().write(buf).with_err_path(|| self.path()) } @@ -915,7 +934,7 @@ impl Write for NamedTempFile { } } -impl<'a> Write for &'a NamedTempFile { +impl Write for &NamedTempFile<File> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.as_file().write(buf).with_err_path(|| self.path()) } @@ -925,20 +944,23 @@ impl<'a> Write for &'a NamedTempFile { } } -impl Seek for NamedTempFile { +impl<F: Seek> Seek for NamedTempFile<F> { fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { self.as_file_mut().seek(pos).with_err_path(|| self.path()) } } -impl<'a> Seek for &'a NamedTempFile { +impl Seek for &NamedTempFile<File> { fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { self.as_file().seek(pos).with_err_path(|| self.path()) } } #[cfg(unix)] -impl std::os::unix::io::AsRawFd for NamedTempFile { +impl<F> std::os::unix::io::AsRawFd for NamedTempFile<F> +where + F: std::os::unix::io::AsRawFd, +{ #[inline] fn as_raw_fd(&self) -> std::os::unix::io::RawFd { self.as_file().as_raw_fd() @@ -946,7 +968,10 @@ impl std::os::unix::io::AsRawFd for NamedTempFile { } #[cfg(windows)] -impl std::os::windows::io::AsRawHandle for NamedTempFile { +impl<F> std::os::windows::io::AsRawHandle for NamedTempFile<F> +where + F: std::os::windows::io::AsRawHandle, +{ #[inline] fn as_raw_handle(&self) -> std::os::windows::io::RawHandle { self.as_file().as_raw_handle() |