6 use std
::fs
::{self, File}
;
7 use std
::io
::{self, Read, Seek, SeekFrom, Write}
;
10 use std
::path
::{Path, PathBuf}
;
16 /// Create a new temporary file.
18 /// The file will be created in the location returned by [`std::env::temp_dir()`].
22 /// This variant is secure/reliable in the presence of a pathological temporary file cleaner.
24 /// # Resource Leaking
26 /// The temporary file will be automatically removed by the OS when the last handle to it is closed.
27 /// This doesn't rely on Rust destructors being run, so will (almost) never fail to clean up the temporary file.
31 /// If the file can not be created, `Err` is returned.
36 /// # extern crate tempfile;
37 /// use tempfile::tempfile;
38 /// use std::io::{self, Write};
41 /// # if let Err(_) = run() {
42 /// # ::std::process::exit(1);
45 /// # fn run() -> Result<(), io::Error> {
46 /// // Create a file inside of `std::env::temp_dir()`.
47 /// let mut file = tempfile()?;
49 /// writeln!(file, "Brian was here. Briefly.")?;
54 /// [`std::env::temp_dir()`]: https://doc.rust-lang.org/std/env/fn.temp_dir.html
55 pub fn tempfile() -> io
::Result
<File
> {
56 tempfile_in(&env
::temp_dir())
59 /// Create a new temporary file in the specified directory.
63 /// This variant is secure/reliable in the presence of a pathological temporary file cleaner.
64 /// If the temporary file isn't created in [`std::env::temp_dir()`] then temporary file cleaners aren't an issue.
66 /// # Resource Leaking
68 /// The temporary file will be automatically removed by the OS when the last handle to it is closed.
69 /// This doesn't rely on Rust destructors being run, so will (almost) never fail to clean up the temporary file.
73 /// If the file can not be created, `Err` is returned.
78 /// # extern crate tempfile;
79 /// use tempfile::tempfile_in;
80 /// use std::io::{self, Write};
83 /// # if let Err(_) = run() {
84 /// # ::std::process::exit(1);
87 /// # fn run() -> Result<(), io::Error> {
88 /// // Create a file inside of the current working directory
89 /// let mut file = tempfile_in("./")?;
91 /// writeln!(file, "Brian was here. Briefly.")?;
96 /// [`std::env::temp_dir()`]: https://doc.rust-lang.org/std/env/fn.temp_dir.html
97 pub fn tempfile_in
<P
: AsRef
<Path
>>(dir
: P
) -> io
::Result
<File
> {
98 imp
::create(dir
.as_ref())
101 /// Error returned when persisting a temporary file path fails.
103 pub struct PathPersistError
{
104 /// The underlying IO error.
105 pub error
: io
::Error
,
106 /// The temporary file path that couldn't be persisted.
110 impl From
<PathPersistError
> for io
::Error
{
112 fn from(error
: PathPersistError
) -> io
::Error
{
117 impl From
<PathPersistError
> for TempPath
{
119 fn from(error
: PathPersistError
) -> TempPath
{
124 impl fmt
::Display
for PathPersistError
{
125 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
126 write
!(f
, "failed to persist temporary file path: {}", self.error
)
130 impl error
::Error
for PathPersistError
{
131 fn description(&self) -> &str {
132 "failed to persist temporary file path"
135 fn cause(&self) -> Option
<&error
::Error
> {
140 /// A path to a named temporary file without an open file handle.
142 /// This is useful when the temporary file needs to be used by a child process,
145 /// When dropped, the temporary file is deleted.
146 pub struct TempPath
{
151 /// Close and remove the temporary file.
153 /// Use this if you want to detect errors in deleting the file.
157 /// If the file cannot be deleted, `Err` is returned.
162 /// # extern crate tempfile;
164 /// use tempfile::NamedTempFile;
167 /// # if let Err(_) = run() {
168 /// # ::std::process::exit(1);
171 /// # fn run() -> Result<(), io::Error> {
172 /// let file = NamedTempFile::new()?;
174 /// // Close the file, but keep the path to it around.
175 /// let path = file.into_temp_path();
177 /// // By closing the `TempPath` explicitly, we can check that it has
178 /// // been deleted successfully. If we don't close it explicitly, the
179 /// // file will still be deleted when `file` goes out of scope, but we
180 /// // won't know whether deleting the file succeeded.
185 pub fn close(mut self) -> io
::Result
<()> {
186 let result
= fs
::remove_file(&self.path
);
187 mem
::replace(&mut self.path
, PathBuf
::new());
192 /// Persist the temporary file at the target path.
194 /// If a file exists at the target path, persist will atomically replace it.
195 /// If this method fails, it will return `self` in the resulting
196 /// [`PathPersistError`].
198 /// Note: Temporary files cannot be persisted across filesystems.
202 /// Only use this method if you're positive that a temporary file cleaner
203 /// won't have deleted your file. Otherwise, you might end up persisting an
204 /// attacker controlled file.
208 /// If the file cannot be moved to the new location, `Err` is returned.
213 /// # use std::io::{self, Write};
214 /// # extern crate tempfile;
215 /// use tempfile::NamedTempFile;
218 /// # if let Err(_) = run() {
219 /// # ::std::process::exit(1);
222 /// # fn run() -> Result<(), io::Error> {
223 /// let mut file = NamedTempFile::new()?;
224 /// writeln!(file, "Brian was here. Briefly.")?;
226 /// let path = file.into_temp_path();
227 /// path.persist("./saved_file.txt")?;
232 /// [`PathPersistError`]: struct.PathPersistError.html
233 pub fn persist
<P
: AsRef
<Path
>>(mut self, new_path
: P
) -> Result
<(), PathPersistError
> {
234 match imp
::persist(&self.path
, new_path
.as_ref(), true) {
236 // Don't drop `self`. We don't want to try deleting the old
237 // temporary file path. (It'll fail, but the failure is never
239 mem
::replace(&mut self.path
, PathBuf
::new());
243 Err(e
) => Err(PathPersistError
{
250 /// Persist the temporary file at the target path iff no file exists there.
252 /// If a file exists at the target path, fail. If this method fails, it will
253 /// return `self` in the resulting [`PathPersistError`].
255 /// Note: Temporary files cannot be persisted across filesystems. Also Note:
256 /// This method is not atomic. It can leave the original link to the
257 /// temporary file behind.
261 /// Only use this method if you're positive that a temporary file cleaner
262 /// won't have deleted your file. Otherwise, you might end up persisting an
263 /// attacker controlled file.
267 /// If the file cannot be moved to the new location or a file already exists
268 /// there, `Err` is returned.
273 /// # use std::io::{self, Write};
274 /// # extern crate tempfile;
275 /// use tempfile::NamedTempFile;
278 /// # if let Err(_) = run() {
279 /// # ::std::process::exit(1);
282 /// # fn run() -> Result<(), io::Error> {
283 /// let mut file = NamedTempFile::new()?;
284 /// writeln!(file, "Brian was here. Briefly.")?;
286 /// let path = file.into_temp_path();
287 /// path.persist_noclobber("./saved_file.txt")?;
292 /// [`PathPersistError`]: struct.PathPersistError.html
293 pub fn persist_noclobber
<P
: AsRef
<Path
>>(
296 ) -> Result
<(), PathPersistError
> {
297 match imp
::persist(&self.path
, new_path
.as_ref(), false) {
299 // Don't drop `self`. We don't want to try deleting the old
300 // temporary file path. (It'll fail, but the failure is never
302 mem
::replace(&mut self.path
, PathBuf
::new());
306 Err(e
) => Err(PathPersistError
{
314 impl fmt
::Debug
for TempPath
{
315 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
320 impl Drop
for TempPath
{
322 let _
= fs
::remove_file(&self.path
);
326 impl Deref
for TempPath
{
329 fn deref(&self) -> &Path
{
334 impl AsRef
<Path
> for TempPath
{
335 fn as_ref(&self) -> &Path
{
340 impl AsRef
<OsStr
> for TempPath
{
341 fn as_ref(&self) -> &OsStr
{
342 self.path
.as_os_str()
346 /// A named temporary file.
348 /// The default constructor, [`NamedTempFile::new()`], creates files in
349 /// the location returned by [`std::env::temp_dir()`], but `NamedTempFile`
350 /// can be configured to manage a temporary file in any location
351 /// by constructing with [`NamedTempFile::new_in()`].
355 /// This variant is *NOT* secure/reliable in the presence of a pathological temporary file cleaner.
357 /// # Resource Leaking
359 /// If the program exits before the `NamedTempFile` destructor is
360 /// run, such as via [`std::process::exit()`], by segfaulting, or by
361 /// receiving a signal like `SIGINT`, then the temporary file
362 /// will not be deleted.
364 /// Use the [`tempfile()`] function unless you absolutely need a named file.
366 /// [`tempfile()`]: fn.tempfile.html
367 /// [`NamedTempFile::new()`]: #method.new
368 /// [`NamedTempFile::new_in()`]: #method.new_in
369 /// [`std::env::temp_dir()`]: https://doc.rust-lang.org/std/env/fn.temp_dir.html
370 /// [`std::process::exit()`]: http://doc.rust-lang.org/std/process/fn.exit.html
371 pub struct NamedTempFile
{
376 impl fmt
::Debug
for NamedTempFile
{
377 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
378 write
!(f
, "NamedTempFile({:?})", self.path
)
382 impl AsRef
<Path
> for NamedTempFile
{
384 fn as_ref(&self) -> &Path
{
389 /// Error returned when persisting a temporary file fails.
391 pub struct PersistError
{
392 /// The underlying IO error.
393 pub error
: io
::Error
,
394 /// The temporary file that couldn't be persisted.
395 pub file
: NamedTempFile
,
398 impl From
<PersistError
> for io
::Error
{
400 fn from(error
: PersistError
) -> io
::Error
{
405 impl From
<PersistError
> for NamedTempFile
{
407 fn from(error
: PersistError
) -> NamedTempFile
{
412 impl fmt
::Display
for PersistError
{
413 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
414 write
!(f
, "failed to persist temporary file: {}", self.error
)
418 impl error
::Error
for PersistError
{
419 fn description(&self) -> &str {
420 "failed to persist temporary file"
422 fn cause(&self) -> Option
<&error
::Error
> {
428 /// Create a new named temporary file.
430 /// See [`Builder`] for more configuration.
434 /// This will create a temporary file in the default temporary file
435 /// directory (platform dependent). These directories are often patrolled by temporary file
436 /// cleaners so only use this method if you're *positive* that the temporary file cleaner won't
437 /// delete your file.
439 /// Reasons to use this method:
441 /// 1. The file has a short lifetime and your temporary file cleaner is
442 /// sane (doesn't delete recently accessed files).
444 /// 2. You trust every user on your system (i.e. you are the only user).
446 /// 3. You have disabled your system's temporary file cleaner or verified
447 /// that your system doesn't have a temporary file cleaner.
449 /// Reasons not to use this method:
451 /// 1. You'll fix it later. No you won't.
453 /// 2. You don't care about the security of the temporary file. If none of
454 /// the "reasons to use this method" apply, referring to a temporary
455 /// file by name may allow an attacker to create/overwrite your
456 /// non-temporary files. There are exceptions but if you don't already
457 /// know them, don't use this method.
461 /// If the file can not be created, `Err` is returned.
465 /// Create a named temporary file and write some data to it:
468 /// # use std::io::{self, Write};
469 /// # extern crate tempfile;
470 /// use tempfile::NamedTempFile;
473 /// # if let Err(_) = run() {
474 /// # ::std::process::exit(1);
477 /// # fn run() -> Result<(), ::std::io::Error> {
478 /// let mut file = NamedTempFile::new()?;
480 /// writeln!(file, "Brian was here. Briefly.")?;
485 /// [`Builder`]: struct.Builder.html
486 pub fn new() -> io
::Result
<NamedTempFile
> {
487 Builder
::new().tempfile()
490 /// Create a new named temporary file in the specified directory.
492 /// See [`NamedTempFile::new()`] for details.
494 /// [`NamedTempFile::new()`]: #method.new_in
495 pub fn new_in
<P
: AsRef
<Path
>>(dir
: P
) -> io
::Result
<NamedTempFile
> {
496 Builder
::new().tempfile_in(dir
)
499 /// Get the temporary file's path.
503 /// Only use this method if you're positive that a
504 /// temporary file cleaner won't have deleted your file. Otherwise, the path
505 /// returned by this method may refer to an attacker controlled file.
510 /// # use std::io::{self, Write};
511 /// # extern crate tempfile;
512 /// use tempfile::NamedTempFile;
515 /// # if let Err(_) = run() {
516 /// # ::std::process::exit(1);
519 /// # fn run() -> Result<(), ::std::io::Error> {
520 /// let file = NamedTempFile::new()?;
522 /// println!("{:?}", file.path());
527 pub fn path(&self) -> &Path
{
531 /// Close and remove the temporary file.
533 /// Use this if you want to detect errors in deleting the file.
537 /// If the file cannot be deleted, `Err` is returned.
542 /// # extern crate tempfile;
544 /// use tempfile::NamedTempFile;
547 /// # if let Err(_) = run() {
548 /// # ::std::process::exit(1);
551 /// # fn run() -> Result<(), io::Error> {
552 /// let file = NamedTempFile::new()?;
554 /// // By closing the `NamedTempFile` explicitly, we can check that it has
555 /// // been deleted successfully. If we don't close it explicitly,
556 /// // the file will still be deleted when `file` goes out
557 /// // of scope, but we won't know whether deleting the file
563 pub fn close(self) -> io
::Result
<()> {
564 let NamedTempFile { path, .. }
= self;
568 /// Persist the temporary file at the target path.
570 /// If a file exists at the target path, persist will atomically replace it.
571 /// If this method fails, it will return `self` in the resulting
572 /// [`PersistError`].
574 /// Note: Temporary files cannot be persisted across filesystems.
578 /// Only use this method if you're positive that a
579 /// temporary file cleaner won't have deleted your file. Otherwise, you
580 /// might end up persisting an attacker controlled file.
584 /// If the file cannot be moved to the new location, `Err` is returned.
589 /// # use std::io::{self, Write};
590 /// # extern crate tempfile;
591 /// use tempfile::NamedTempFile;
594 /// # if let Err(_) = run() {
595 /// # ::std::process::exit(1);
598 /// # fn run() -> Result<(), io::Error> {
599 /// let file = NamedTempFile::new()?;
601 /// let mut persisted_file = file.persist("./saved_file.txt")?;
602 /// writeln!(persisted_file, "Brian was here. Briefly.")?;
607 /// [`PersistError`]: struct.PersistError.html
608 pub fn persist
<P
: AsRef
<Path
>>(self, new_path
: P
) -> Result
<File
, PersistError
> {
609 let NamedTempFile { path, file }
= self;
610 match path
.persist(new_path
) {
613 let PathPersistError { error, path }
= err
;
615 file
: NamedTempFile { path, file }
,
622 /// Persist the temporary file at the target path iff no file exists there.
624 /// If a file exists at the target path, fail. If this method fails, it will
625 /// return `self` in the resulting PersistError.
627 /// Note: Temporary files cannot be persisted across filesystems. Also Note:
628 /// This method is not atomic. It can leave the original link to the
629 /// temporary file behind.
633 /// Only use this method if you're positive that a
634 /// temporary file cleaner won't have deleted your file. Otherwise, you
635 /// might end up persisting an attacker controlled file.
639 /// If the file cannot be moved to the new location or a file already exists there,
640 /// `Err` is returned.
645 /// # use std::io::{self, Write};
646 /// # extern crate tempfile;
647 /// use tempfile::NamedTempFile;
650 /// # if let Err(_) = run() {
651 /// # ::std::process::exit(1);
654 /// # fn run() -> Result<(), io::Error> {
655 /// let file = NamedTempFile::new()?;
657 /// let mut persisted_file = file.persist_noclobber("./saved_file.txt")?;
658 /// writeln!(persisted_file, "Brian was here. Briefly.")?;
662 pub fn persist_noclobber
<P
: AsRef
<Path
>>(self, new_path
: P
) -> Result
<File
, PersistError
> {
663 let NamedTempFile { path, file }
= self;
664 match path
.persist_noclobber(new_path
) {
667 let PathPersistError { error, path }
= err
;
669 file
: NamedTempFile { path, file }
,
676 /// Reopen the temporary file.
678 /// This function is useful when you need multiple independent handles to
679 /// the same file. It's perfectly fine to drop the original `NamedTempFile`
680 /// while holding on to `File`s returned by this function; the `File`s will
681 /// remain usable. However, they may not be nameable.
685 /// If the file cannot be reopened, `Err` is returned.
691 /// # extern crate tempfile;
692 /// use tempfile::NamedTempFile;
695 /// # if let Err(_) = run() {
696 /// # ::std::process::exit(1);
699 /// # fn run() -> Result<(), io::Error> {
700 /// let file = NamedTempFile::new()?;
702 /// let another_handle = file.reopen()?;
706 pub fn reopen(&self) -> io
::Result
<File
> {
707 imp
::reopen(self.as_file(), NamedTempFile
::path(self))
710 /// Get a reference to the underlying file.
711 pub fn as_file(&self) -> &File
{
715 /// Get a mutable reference to the underlying file.
716 pub fn as_file_mut(&mut self) -> &mut File
{
720 /// Convert the temporary file into a `std::fs::File`.
722 /// The inner file will be deleted.
723 pub fn into_file(self) -> File
{
727 /// Closes the file, leaving only the temporary file path.
729 /// This is useful when another process must be able to open the temporary
731 pub fn into_temp_path(self) -> TempPath
{
736 impl Read
for NamedTempFile
{
737 fn read(&mut self, buf
: &mut [u8]) -> io
::Result
<usize> {
738 self.as_file_mut().read(buf
)
742 impl<'a
> Read
for &'a NamedTempFile
{
743 fn read(&mut self, buf
: &mut [u8]) -> io
::Result
<usize> {
744 self.as_file().read(buf
)
748 impl Write
for NamedTempFile
{
749 fn write(&mut self, buf
: &[u8]) -> io
::Result
<usize> {
750 self.as_file_mut().write(buf
)
753 fn flush(&mut self) -> io
::Result
<()> {
754 self.as_file_mut().flush()
758 impl<'a
> Write
for &'a NamedTempFile
{
759 fn write(&mut self, buf
: &[u8]) -> io
::Result
<usize> {
760 self.as_file().write(buf
)
763 fn flush(&mut self) -> io
::Result
<()> {
764 self.as_file().flush()
768 impl Seek
for NamedTempFile
{
769 fn seek(&mut self, pos
: SeekFrom
) -> io
::Result
<u64> {
770 self.as_file_mut().seek(pos
)
774 impl<'a
> Seek
for &'a NamedTempFile
{
775 fn seek(&mut self, pos
: SeekFrom
) -> io
::Result
<u64> {
776 self.as_file().seek(pos
)
781 impl std
::os
::unix
::io
::AsRawFd
for NamedTempFile
{
783 fn as_raw_fd(&self) -> std
::os
::unix
::io
::RawFd
{
784 self.as_file().as_raw_fd()
789 impl std
::os
::windows
::io
::AsRawHandle
for NamedTempFile
{
791 fn as_raw_handle(&self) -> std
::os
::windows
::io
::RawHandle
{
792 self.as_file().as_raw_handle()
797 pub fn create_named(path
: PathBuf
) -> io
::Result
<NamedTempFile
> {
798 imp
::create_named(&path
).map(|file
| NamedTempFile
{
799 path
: TempPath { path }
,