6 use std
::fs
::{self, File}
;
7 use std
::io
::{self, Read, Seek, SeekFrom, Write}
;
10 use std
::path
::{Path, PathBuf}
;
12 use error
::IoResultExt
;
17 /// Create a new temporary file.
19 /// The file will be created in the location returned by [`std::env::temp_dir()`].
23 /// This variant is secure/reliable in the presence of a pathological temporary file cleaner.
25 /// # Resource Leaking
27 /// The temporary file will be automatically removed by the OS when the last handle to it is closed.
28 /// This doesn't rely on Rust destructors being run, so will (almost) never fail to clean up the temporary file.
32 /// If the file can not be created, `Err` is returned.
37 /// # extern crate tempfile;
38 /// use tempfile::tempfile;
39 /// use std::io::{self, Write};
42 /// # if let Err(_) = run() {
43 /// # ::std::process::exit(1);
46 /// # fn run() -> Result<(), io::Error> {
47 /// // Create a file inside of `std::env::temp_dir()`.
48 /// let mut file = tempfile()?;
50 /// writeln!(file, "Brian was here. Briefly.")?;
55 /// [`std::env::temp_dir()`]: https://doc.rust-lang.org/std/env/fn.temp_dir.html
56 pub fn tempfile() -> io
::Result
<File
> {
57 tempfile_in(&env
::temp_dir())
60 /// Create a new temporary file in the specified directory.
64 /// This variant is secure/reliable in the presence of a pathological temporary file cleaner.
65 /// If the temporary file isn't created in [`std::env::temp_dir()`] then temporary file cleaners aren't an issue.
67 /// # Resource Leaking
69 /// The temporary file will be automatically removed by the OS when the last handle to it is closed.
70 /// This doesn't rely on Rust destructors being run, so will (almost) never fail to clean up the temporary file.
74 /// If the file can not be created, `Err` is returned.
79 /// # extern crate tempfile;
80 /// use tempfile::tempfile_in;
81 /// use std::io::{self, Write};
84 /// # if let Err(_) = run() {
85 /// # ::std::process::exit(1);
88 /// # fn run() -> Result<(), io::Error> {
89 /// // Create a file inside of the current working directory
90 /// let mut file = tempfile_in("./")?;
92 /// writeln!(file, "Brian was here. Briefly.")?;
97 /// [`std::env::temp_dir()`]: https://doc.rust-lang.org/std/env/fn.temp_dir.html
98 pub fn tempfile_in
<P
: AsRef
<Path
>>(dir
: P
) -> io
::Result
<File
> {
99 imp
::create(dir
.as_ref())
102 /// Error returned when persisting a temporary file path fails.
104 pub struct PathPersistError
{
105 /// The underlying IO error.
106 pub error
: io
::Error
,
107 /// The temporary file path that couldn't be persisted.
111 impl From
<PathPersistError
> for io
::Error
{
113 fn from(error
: PathPersistError
) -> io
::Error
{
118 impl From
<PathPersistError
> for TempPath
{
120 fn from(error
: PathPersistError
) -> TempPath
{
125 impl fmt
::Display
for PathPersistError
{
126 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
127 write
!(f
, "failed to persist temporary file path: {}", self.error
)
131 impl error
::Error
for PathPersistError
{
132 fn description(&self) -> &str {
133 "failed to persist temporary file path"
136 fn cause(&self) -> Option
<&error
::Error
> {
141 /// A path to a named temporary file without an open file handle.
143 /// This is useful when the temporary file needs to be used by a child process,
146 /// When dropped, the temporary file is deleted.
147 pub struct TempPath
{
152 /// Close and remove the temporary file.
154 /// Use this if you want to detect errors in deleting the file.
158 /// If the file cannot be deleted, `Err` is returned.
163 /// # extern crate tempfile;
165 /// use tempfile::NamedTempFile;
168 /// # if let Err(_) = run() {
169 /// # ::std::process::exit(1);
172 /// # fn run() -> Result<(), io::Error> {
173 /// let file = NamedTempFile::new()?;
175 /// // Close the file, but keep the path to it around.
176 /// let path = file.into_temp_path();
178 /// // By closing the `TempPath` explicitly, we can check that it has
179 /// // been deleted successfully. If we don't close it explicitly, the
180 /// // file will still be deleted when `file` goes out of scope, but we
181 /// // won't know whether deleting the file succeeded.
186 pub fn close(mut self) -> io
::Result
<()> {
187 let result
= fs
::remove_file(&self.path
).with_err_path(|| &self.path
);
188 mem
::replace(&mut self.path
, PathBuf
::new());
193 /// Persist the temporary file at the target path.
195 /// If a file exists at the target path, persist will atomically replace it.
196 /// If this method fails, it will return `self` in the resulting
197 /// [`PathPersistError`].
199 /// Note: Temporary files cannot be persisted across filesystems.
203 /// Only use this method if you're positive that a temporary file cleaner
204 /// won't have deleted your file. Otherwise, you might end up persisting an
205 /// attacker controlled file.
209 /// If the file cannot be moved to the new location, `Err` is returned.
214 /// # use std::io::{self, Write};
215 /// # extern crate tempfile;
216 /// use tempfile::NamedTempFile;
219 /// # if let Err(_) = run() {
220 /// # ::std::process::exit(1);
223 /// # fn run() -> Result<(), io::Error> {
224 /// let mut file = NamedTempFile::new()?;
225 /// writeln!(file, "Brian was here. Briefly.")?;
227 /// let path = file.into_temp_path();
228 /// path.persist("./saved_file.txt")?;
233 /// [`PathPersistError`]: struct.PathPersistError.html
234 pub fn persist
<P
: AsRef
<Path
>>(mut self, new_path
: P
) -> Result
<(), PathPersistError
> {
235 match imp
::persist(&self.path
, new_path
.as_ref(), true) {
237 // Don't drop `self`. We don't want to try deleting the old
238 // temporary file path. (It'll fail, but the failure is never
240 mem
::replace(&mut self.path
, PathBuf
::new());
244 Err(e
) => Err(PathPersistError
{
251 /// Persist the temporary file at the target path iff no file exists there.
253 /// If a file exists at the target path, fail. If this method fails, it will
254 /// return `self` in the resulting [`PathPersistError`].
256 /// Note: Temporary files cannot be persisted across filesystems. Also Note:
257 /// This method is not atomic. It can leave the original link to the
258 /// temporary file behind.
262 /// Only use this method if you're positive that a temporary file cleaner
263 /// won't have deleted your file. Otherwise, you might end up persisting an
264 /// attacker controlled file.
268 /// If the file cannot be moved to the new location or a file already exists
269 /// there, `Err` is returned.
274 /// # use std::io::{self, Write};
275 /// # extern crate tempfile;
276 /// use tempfile::NamedTempFile;
279 /// # if let Err(_) = run() {
280 /// # ::std::process::exit(1);
283 /// # fn run() -> Result<(), io::Error> {
284 /// let mut file = NamedTempFile::new()?;
285 /// writeln!(file, "Brian was here. Briefly.")?;
287 /// let path = file.into_temp_path();
288 /// path.persist_noclobber("./saved_file.txt")?;
293 /// [`PathPersistError`]: struct.PathPersistError.html
294 pub fn persist_noclobber
<P
: AsRef
<Path
>>(
297 ) -> Result
<(), PathPersistError
> {
298 match imp
::persist(&self.path
, new_path
.as_ref(), false) {
300 // Don't drop `self`. We don't want to try deleting the old
301 // temporary file path. (It'll fail, but the failure is never
303 mem
::replace(&mut self.path
, PathBuf
::new());
307 Err(e
) => Err(PathPersistError
{
314 /// Keep the temporary file from being deleted. This function will turn the
315 /// temporary file into a non-temporary file without moving it.
320 /// On some platforms (e.g., Windows), we need to mark the file as
321 /// non-temporary. This operation could fail.
326 /// # use std::io::{self, Write};
327 /// # extern crate tempfile;
328 /// use tempfile::NamedTempFile;
331 /// # if let Err(_) = run() {
332 /// # ::std::process::exit(1);
335 /// # fn run() -> Result<(), io::Error> {
336 /// let mut file = NamedTempFile::new()?;
337 /// writeln!(file, "Brian was here. Briefly.")?;
339 /// let path = file.into_temp_path();
340 /// let path = path.keep()?;
345 /// [`PathPersistError`]: struct.PathPersistError.html
346 pub fn keep(mut self) -> Result
<PathBuf
, PathPersistError
> {
347 match imp
::keep(&self.path
) {
349 // Don't drop `self`. We don't want to try deleting the old
350 // temporary file path. (It'll fail, but the failure is never
352 let mut path
= PathBuf
::new();
353 mem
::swap(&mut self.path
, &mut path
);
357 Err(e
) => Err(PathPersistError
{
365 impl fmt
::Debug
for TempPath
{
366 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
371 impl Drop
for TempPath
{
373 let _
= fs
::remove_file(&self.path
);
377 impl Deref
for TempPath
{
380 fn deref(&self) -> &Path
{
385 impl AsRef
<Path
> for TempPath
{
386 fn as_ref(&self) -> &Path
{
391 impl AsRef
<OsStr
> for TempPath
{
392 fn as_ref(&self) -> &OsStr
{
393 self.path
.as_os_str()
397 /// A named temporary file.
399 /// The default constructor, [`NamedTempFile::new()`], creates files in
400 /// the location returned by [`std::env::temp_dir()`], but `NamedTempFile`
401 /// can be configured to manage a temporary file in any location
402 /// by constructing with [`NamedTempFile::new_in()`].
406 /// This variant is *NOT* secure/reliable in the presence of a pathological temporary file cleaner.
408 /// # Resource Leaking
410 /// If the program exits before the `NamedTempFile` destructor is
411 /// run, such as via [`std::process::exit()`], by segfaulting, or by
412 /// receiving a signal like `SIGINT`, then the temporary file
413 /// will not be deleted.
415 /// Use the [`tempfile()`] function unless you absolutely need a named file.
417 /// [`tempfile()`]: fn.tempfile.html
418 /// [`NamedTempFile::new()`]: #method.new
419 /// [`NamedTempFile::new_in()`]: #method.new_in
420 /// [`std::env::temp_dir()`]: https://doc.rust-lang.org/std/env/fn.temp_dir.html
421 /// [`std::process::exit()`]: http://doc.rust-lang.org/std/process/fn.exit.html
422 pub struct NamedTempFile
{
427 impl fmt
::Debug
for NamedTempFile
{
428 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
429 write
!(f
, "NamedTempFile({:?})", self.path
)
433 impl AsRef
<Path
> for NamedTempFile
{
435 fn as_ref(&self) -> &Path
{
440 /// Error returned when persisting a temporary file fails.
442 pub struct PersistError
{
443 /// The underlying IO error.
444 pub error
: io
::Error
,
445 /// The temporary file that couldn't be persisted.
446 pub file
: NamedTempFile
,
449 impl From
<PersistError
> for io
::Error
{
451 fn from(error
: PersistError
) -> io
::Error
{
456 impl From
<PersistError
> for NamedTempFile
{
458 fn from(error
: PersistError
) -> NamedTempFile
{
463 impl fmt
::Display
for PersistError
{
464 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
465 write
!(f
, "failed to persist temporary file: {}", self.error
)
469 impl error
::Error
for PersistError
{
470 fn description(&self) -> &str {
471 "failed to persist temporary file"
473 fn cause(&self) -> Option
<&error
::Error
> {
479 /// Create a new named temporary file.
481 /// See [`Builder`] for more configuration.
485 /// This will create a temporary file in the default temporary file
486 /// directory (platform dependent). These directories are often patrolled by temporary file
487 /// cleaners so only use this method if you're *positive* that the temporary file cleaner won't
488 /// delete your file.
490 /// Reasons to use this method:
492 /// 1. The file has a short lifetime and your temporary file cleaner is
493 /// sane (doesn't delete recently accessed files).
495 /// 2. You trust every user on your system (i.e. you are the only user).
497 /// 3. You have disabled your system's temporary file cleaner or verified
498 /// that your system doesn't have a temporary file cleaner.
500 /// Reasons not to use this method:
502 /// 1. You'll fix it later. No you won't.
504 /// 2. You don't care about the security of the temporary file. If none of
505 /// the "reasons to use this method" apply, referring to a temporary
506 /// file by name may allow an attacker to create/overwrite your
507 /// non-temporary files. There are exceptions but if you don't already
508 /// know them, don't use this method.
512 /// If the file can not be created, `Err` is returned.
516 /// Create a named temporary file and write some data to it:
519 /// # use std::io::{self, Write};
520 /// # extern crate tempfile;
521 /// use tempfile::NamedTempFile;
524 /// # if let Err(_) = run() {
525 /// # ::std::process::exit(1);
528 /// # fn run() -> Result<(), ::std::io::Error> {
529 /// let mut file = NamedTempFile::new()?;
531 /// writeln!(file, "Brian was here. Briefly.")?;
536 /// [`Builder`]: struct.Builder.html
537 pub fn new() -> io
::Result
<NamedTempFile
> {
538 Builder
::new().tempfile()
541 /// Create a new named temporary file in the specified directory.
543 /// See [`NamedTempFile::new()`] for details.
545 /// [`NamedTempFile::new()`]: #method.new_in
546 pub fn new_in
<P
: AsRef
<Path
>>(dir
: P
) -> io
::Result
<NamedTempFile
> {
547 Builder
::new().tempfile_in(dir
)
550 /// Get the temporary file's path.
554 /// Only use this method if you're positive that a
555 /// temporary file cleaner won't have deleted your file. Otherwise, the path
556 /// returned by this method may refer to an attacker controlled file.
561 /// # use std::io::{self, Write};
562 /// # extern crate tempfile;
563 /// use tempfile::NamedTempFile;
566 /// # if let Err(_) = run() {
567 /// # ::std::process::exit(1);
570 /// # fn run() -> Result<(), ::std::io::Error> {
571 /// let file = NamedTempFile::new()?;
573 /// println!("{:?}", file.path());
578 pub fn path(&self) -> &Path
{
582 /// Close and remove the temporary file.
584 /// Use this if you want to detect errors in deleting the file.
588 /// If the file cannot be deleted, `Err` is returned.
593 /// # extern crate tempfile;
595 /// use tempfile::NamedTempFile;
598 /// # if let Err(_) = run() {
599 /// # ::std::process::exit(1);
602 /// # fn run() -> Result<(), io::Error> {
603 /// let file = NamedTempFile::new()?;
605 /// // By closing the `NamedTempFile` explicitly, we can check that it has
606 /// // been deleted successfully. If we don't close it explicitly,
607 /// // the file will still be deleted when `file` goes out
608 /// // of scope, but we won't know whether deleting the file
614 pub fn close(self) -> io
::Result
<()> {
615 let NamedTempFile { path, .. }
= self;
619 /// Persist the temporary file at the target path.
621 /// If a file exists at the target path, persist will atomically replace it.
622 /// If this method fails, it will return `self` in the resulting
623 /// [`PersistError`].
625 /// Note: Temporary files cannot be persisted across filesystems.
629 /// Only use this method if you're positive that a
630 /// temporary file cleaner won't have deleted your file. Otherwise, you
631 /// might end up persisting an attacker controlled file.
635 /// If the file cannot be moved to the new location, `Err` is returned.
640 /// # use std::io::{self, Write};
641 /// # extern crate tempfile;
642 /// use tempfile::NamedTempFile;
645 /// # if let Err(_) = run() {
646 /// # ::std::process::exit(1);
649 /// # fn run() -> Result<(), io::Error> {
650 /// let file = NamedTempFile::new()?;
652 /// let mut persisted_file = file.persist("./saved_file.txt")?;
653 /// writeln!(persisted_file, "Brian was here. Briefly.")?;
658 /// [`PersistError`]: struct.PersistError.html
659 pub fn persist
<P
: AsRef
<Path
>>(self, new_path
: P
) -> Result
<File
, PersistError
> {
660 let NamedTempFile { path, file }
= self;
661 match path
.persist(new_path
) {
664 let PathPersistError { error, path }
= err
;
666 file
: NamedTempFile { path, file }
,
673 /// Persist the temporary file at the target path iff no file exists there.
675 /// If a file exists at the target path, fail. If this method fails, it will
676 /// return `self` in the resulting PersistError.
678 /// Note: Temporary files cannot be persisted across filesystems. Also Note:
679 /// This method is not atomic. It can leave the original link to the
680 /// temporary file behind.
684 /// Only use this method if you're positive that a
685 /// temporary file cleaner won't have deleted your file. Otherwise, you
686 /// might end up persisting an attacker controlled file.
690 /// If the file cannot be moved to the new location or a file already exists there,
691 /// `Err` is returned.
696 /// # use std::io::{self, Write};
697 /// # extern crate tempfile;
698 /// use tempfile::NamedTempFile;
701 /// # if let Err(_) = run() {
702 /// # ::std::process::exit(1);
705 /// # fn run() -> Result<(), io::Error> {
706 /// let file = NamedTempFile::new()?;
708 /// let mut persisted_file = file.persist_noclobber("./saved_file.txt")?;
709 /// writeln!(persisted_file, "Brian was here. Briefly.")?;
713 pub fn persist_noclobber
<P
: AsRef
<Path
>>(self, new_path
: P
) -> Result
<File
, PersistError
> {
714 let NamedTempFile { path, file }
= self;
715 match path
.persist_noclobber(new_path
) {
718 let PathPersistError { error, path }
= err
;
720 file
: NamedTempFile { path, file }
,
727 /// Keep the temporary file from being deleted. This function will turn the
728 /// temporary file into a non-temporary file without moving it.
733 /// On some platforms (e.g., Windows), we need to mark the file as
734 /// non-temporary. This operation could fail.
739 /// # use std::io::{self, Write};
740 /// # extern crate tempfile;
741 /// use tempfile::NamedTempFile;
744 /// # if let Err(_) = run() {
745 /// # ::std::process::exit(1);
748 /// # fn run() -> Result<(), io::Error> {
749 /// let mut file = NamedTempFile::new()?;
750 /// writeln!(file, "Brian was here. Briefly.")?;
752 /// let (file, path) = file.keep()?;
757 /// [`PathPersistError`]: struct.PathPersistError.html
758 pub fn keep(self) -> Result
<(File
, PathBuf
), PersistError
> {
759 let (file
, path
) = (self.file
, self.path
);
761 Ok(path
) => Ok((file
, path
)),
762 Err(PathPersistError { error, path }
) => Err(PersistError
{
763 file
: NamedTempFile { path, file }
,
769 /// Reopen the temporary file.
771 /// This function is useful when you need multiple independent handles to
772 /// the same file. It's perfectly fine to drop the original `NamedTempFile`
773 /// while holding on to `File`s returned by this function; the `File`s will
774 /// remain usable. However, they may not be nameable.
778 /// If the file cannot be reopened, `Err` is returned.
784 /// # extern crate tempfile;
785 /// use tempfile::NamedTempFile;
788 /// # if let Err(_) = run() {
789 /// # ::std::process::exit(1);
792 /// # fn run() -> Result<(), io::Error> {
793 /// let file = NamedTempFile::new()?;
795 /// let another_handle = file.reopen()?;
799 pub fn reopen(&self) -> io
::Result
<File
> {
800 imp
::reopen(self.as_file(), NamedTempFile
::path(self))
801 .with_err_path(|| NamedTempFile
::path(self))
804 /// Get a reference to the underlying file.
805 pub fn as_file(&self) -> &File
{
809 /// Get a mutable reference to the underlying file.
810 pub fn as_file_mut(&mut self) -> &mut File
{
814 /// Convert the temporary file into a `std::fs::File`.
816 /// The inner file will be deleted.
817 pub fn into_file(self) -> File
{
821 /// Closes the file, leaving only the temporary file path.
823 /// This is useful when another process must be able to open the temporary
825 pub fn into_temp_path(self) -> TempPath
{
829 /// Converts the named temporary file into its constituent parts.
831 /// Note: When the path is dropped, the file is deleted but the file handle
833 pub fn into_parts(self) -> (File
, TempPath
) {
834 (self.file
, self.path
)
838 impl Read
for NamedTempFile
{
839 fn read(&mut self, buf
: &mut [u8]) -> io
::Result
<usize> {
840 self.as_file_mut().read(buf
).with_err_path(|| self.path())
844 impl<'a
> Read
for &'a NamedTempFile
{
845 fn read(&mut self, buf
: &mut [u8]) -> io
::Result
<usize> {
846 self.as_file().read(buf
).with_err_path(|| self.path())
850 impl Write
for NamedTempFile
{
851 fn write(&mut self, buf
: &[u8]) -> io
::Result
<usize> {
852 self.as_file_mut().write(buf
).with_err_path(|| self.path())
855 fn flush(&mut self) -> io
::Result
<()> {
856 self.as_file_mut().flush().with_err_path(|| self.path())
860 impl<'a
> Write
for &'a NamedTempFile
{
861 fn write(&mut self, buf
: &[u8]) -> io
::Result
<usize> {
862 self.as_file().write(buf
).with_err_path(|| self.path())
865 fn flush(&mut self) -> io
::Result
<()> {
866 self.as_file().flush().with_err_path(|| self.path())
870 impl Seek
for NamedTempFile
{
871 fn seek(&mut self, pos
: SeekFrom
) -> io
::Result
<u64> {
872 self.as_file_mut().seek(pos
).with_err_path(|| self.path())
876 impl<'a
> Seek
for &'a NamedTempFile
{
877 fn seek(&mut self, pos
: SeekFrom
) -> io
::Result
<u64> {
878 self.as_file().seek(pos
).with_err_path(|| self.path())
883 impl std
::os
::unix
::io
::AsRawFd
for NamedTempFile
{
885 fn as_raw_fd(&self) -> std
::os
::unix
::io
::RawFd
{
886 self.as_file().as_raw_fd()
891 impl std
::os
::windows
::io
::AsRawHandle
for NamedTempFile
{
893 fn as_raw_handle(&self) -> std
::os
::windows
::io
::RawHandle
{
894 self.as_file().as_raw_handle()
898 pub(crate) fn create_named(mut path
: PathBuf
) -> io
::Result
<NamedTempFile
> {
899 // Make the path absolute. Otherwise, changing directories could cause us to
900 // delete the wrong file.
901 if !path
.is_absolute() {
902 path
= env
::current_dir()?
.join(path
)
904 imp
::create_named(&path
)
905 .with_err_path(|| path
.clone())
906 .map(|file
| NamedTempFile
{
907 path
: TempPath { path }
,