• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::env;
2 use std::error;
3 use std::ffi::OsStr;
4 use std::fmt;
5 use std::fs::{self, File, OpenOptions};
6 use std::io::{self, Read, Seek, SeekFrom, Write};
7 use std::mem;
8 use std::ops::Deref;
9 use std::path::{Path, PathBuf};
10 
11 use crate::error::IoResultExt;
12 use crate::Builder;
13 
14 mod imp;
15 
16 /// Create a new temporary file.
17 ///
18 /// The file will be created in the location returned by [`std::env::temp_dir()`].
19 ///
20 /// # Security
21 ///
22 /// This variant is secure/reliable in the presence of a pathological temporary file cleaner.
23 ///
24 /// # Resource Leaking
25 ///
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.
28 ///
29 /// # Errors
30 ///
31 /// If the file can not be created, `Err` is returned.
32 ///
33 /// # Examples
34 ///
35 /// ```
36 /// use tempfile::tempfile;
37 /// use std::io::{self, Write};
38 ///
39 /// # fn main() {
40 /// #     if let Err(_) = run() {
41 /// #         ::std::process::exit(1);
42 /// #     }
43 /// # }
44 /// # fn run() -> Result<(), io::Error> {
45 /// // Create a file inside of `std::env::temp_dir()`.
46 /// let mut file = tempfile()?;
47 ///
48 /// writeln!(file, "Brian was here. Briefly.")?;
49 /// # Ok(())
50 /// # }
51 /// ```
52 ///
53 /// [`std::env::temp_dir()`]: https://doc.rust-lang.org/std/env/fn.temp_dir.html
tempfile() -> io::Result<File>54 pub fn tempfile() -> io::Result<File> {
55     tempfile_in(&env::temp_dir())
56 }
57 
58 /// Create a new temporary file in the specified directory.
59 ///
60 /// # Security
61 ///
62 /// This variant is secure/reliable in the presence of a pathological temporary file cleaner.
63 /// If the temporary file isn't created in [`std::env::temp_dir()`] then temporary file cleaners aren't an issue.
64 ///
65 /// # Resource Leaking
66 ///
67 /// The temporary file will be automatically removed by the OS when the last handle to it is closed.
68 /// This doesn't rely on Rust destructors being run, so will (almost) never fail to clean up the temporary file.
69 ///
70 /// # Errors
71 ///
72 /// If the file can not be created, `Err` is returned.
73 ///
74 /// # Examples
75 ///
76 /// ```
77 /// use tempfile::tempfile_in;
78 /// use std::io::{self, Write};
79 ///
80 /// # fn main() {
81 /// #     if let Err(_) = run() {
82 /// #         ::std::process::exit(1);
83 /// #     }
84 /// # }
85 /// # fn run() -> Result<(), io::Error> {
86 /// // Create a file inside of the current working directory
87 /// let mut file = tempfile_in("./")?;
88 ///
89 /// writeln!(file, "Brian was here. Briefly.")?;
90 /// # Ok(())
91 /// # }
92 /// ```
93 ///
94 /// [`std::env::temp_dir()`]: https://doc.rust-lang.org/std/env/fn.temp_dir.html
tempfile_in<P: AsRef<Path>>(dir: P) -> io::Result<File>95 pub fn tempfile_in<P: AsRef<Path>>(dir: P) -> io::Result<File> {
96     imp::create(dir.as_ref())
97 }
98 
99 /// Error returned when persisting a temporary file path fails.
100 #[derive(Debug)]
101 pub struct PathPersistError {
102     /// The underlying IO error.
103     pub error: io::Error,
104     /// The temporary file path that couldn't be persisted.
105     pub path: TempPath,
106 }
107 
108 impl From<PathPersistError> for io::Error {
109     #[inline]
from(error: PathPersistError) -> io::Error110     fn from(error: PathPersistError) -> io::Error {
111         error.error
112     }
113 }
114 
115 impl From<PathPersistError> for TempPath {
116     #[inline]
from(error: PathPersistError) -> TempPath117     fn from(error: PathPersistError) -> TempPath {
118         error.path
119     }
120 }
121 
122 impl fmt::Display for PathPersistError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result123     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124         write!(f, "failed to persist temporary file path: {}", self.error)
125     }
126 }
127 
128 impl error::Error for PathPersistError {
source(&self) -> Option<&(dyn error::Error + 'static)>129     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
130         Some(&self.error)
131     }
132 }
133 
134 /// A path to a named temporary file without an open file handle.
135 ///
136 /// This is useful when the temporary file needs to be used by a child process,
137 /// for example.
138 ///
139 /// When dropped, the temporary file is deleted.
140 pub struct TempPath {
141     path: Box<Path>,
142 }
143 
144 impl TempPath {
145     /// Close and remove the temporary file.
146     ///
147     /// Use this if you want to detect errors in deleting the file.
148     ///
149     /// # Errors
150     ///
151     /// If the file cannot be deleted, `Err` is returned.
152     ///
153     /// # Examples
154     ///
155     /// ```no_run
156     /// # use std::io;
157     /// use tempfile::NamedTempFile;
158     ///
159     /// # fn main() {
160     /// #     if let Err(_) = run() {
161     /// #         ::std::process::exit(1);
162     /// #     }
163     /// # }
164     /// # fn run() -> Result<(), io::Error> {
165     /// let file = NamedTempFile::new()?;
166     ///
167     /// // Close the file, but keep the path to it around.
168     /// let path = file.into_temp_path();
169     ///
170     /// // By closing the `TempPath` explicitly, we can check that it has
171     /// // been deleted successfully. If we don't close it explicitly, the
172     /// // file will still be deleted when `file` goes out of scope, but we
173     /// // won't know whether deleting the file succeeded.
174     /// path.close()?;
175     /// # Ok(())
176     /// # }
177     /// ```
close(mut self) -> io::Result<()>178     pub fn close(mut self) -> io::Result<()> {
179         let result = fs::remove_file(&self.path).with_err_path(|| &*self.path);
180         self.path = PathBuf::new().into_boxed_path();
181         mem::forget(self);
182         result
183     }
184 
185     /// Persist the temporary file at the target path.
186     ///
187     /// If a file exists at the target path, persist will atomically replace it.
188     /// If this method fails, it will return `self` in the resulting
189     /// [`PathPersistError`].
190     ///
191     /// Note: Temporary files cannot be persisted across filesystems. Also
192     /// neither the file contents nor the containing directory are
193     /// synchronized, so the update may not yet have reached the disk when
194     /// `persist` returns.
195     ///
196     /// # Security
197     ///
198     /// Only use this method if you're positive that a temporary file cleaner
199     /// won't have deleted your file. Otherwise, you might end up persisting an
200     /// attacker controlled file.
201     ///
202     /// # Errors
203     ///
204     /// If the file cannot be moved to the new location, `Err` is returned.
205     ///
206     /// # Examples
207     ///
208     /// ```no_run
209     /// # use std::io::{self, Write};
210     /// use tempfile::NamedTempFile;
211     ///
212     /// # fn main() {
213     /// #     if let Err(_) = run() {
214     /// #         ::std::process::exit(1);
215     /// #     }
216     /// # }
217     /// # fn run() -> Result<(), io::Error> {
218     /// let mut file = NamedTempFile::new()?;
219     /// writeln!(file, "Brian was here. Briefly.")?;
220     ///
221     /// let path = file.into_temp_path();
222     /// path.persist("./saved_file.txt")?;
223     /// # Ok(())
224     /// # }
225     /// ```
226     ///
227     /// [`PathPersistError`]: struct.PathPersistError.html
persist<P: AsRef<Path>>(mut self, new_path: P) -> Result<(), PathPersistError>228     pub fn persist<P: AsRef<Path>>(mut self, new_path: P) -> Result<(), PathPersistError> {
229         match imp::persist(&self.path, new_path.as_ref(), true) {
230             Ok(_) => {
231                 // Don't drop `self`. We don't want to try deleting the old
232                 // temporary file path. (It'll fail, but the failure is never
233                 // seen.)
234                 self.path = PathBuf::new().into_boxed_path();
235                 mem::forget(self);
236                 Ok(())
237             }
238             Err(e) => Err(PathPersistError {
239                 error: e,
240                 path: self,
241             }),
242         }
243     }
244 
245     /// Persist the temporary file at the target path if and only if no file exists there.
246     ///
247     /// If a file exists at the target path, fail. If this method fails, it will
248     /// return `self` in the resulting [`PathPersistError`].
249     ///
250     /// Note: Temporary files cannot be persisted across filesystems. Also Note:
251     /// This method is not atomic. It can leave the original link to the
252     /// temporary file behind.
253     ///
254     /// # Security
255     ///
256     /// Only use this method if you're positive that a temporary file cleaner
257     /// won't have deleted your file. Otherwise, you might end up persisting an
258     /// attacker controlled file.
259     ///
260     /// # Errors
261     ///
262     /// If the file cannot be moved to the new location or a file already exists
263     /// there, `Err` is returned.
264     ///
265     /// # Examples
266     ///
267     /// ```no_run
268     /// # use std::io::{self, Write};
269     /// use tempfile::NamedTempFile;
270     ///
271     /// # fn main() {
272     /// #     if let Err(_) = run() {
273     /// #         ::std::process::exit(1);
274     /// #     }
275     /// # }
276     /// # fn run() -> Result<(), io::Error> {
277     /// let mut file = NamedTempFile::new()?;
278     /// writeln!(file, "Brian was here. Briefly.")?;
279     ///
280     /// let path = file.into_temp_path();
281     /// path.persist_noclobber("./saved_file.txt")?;
282     /// # Ok(())
283     /// # }
284     /// ```
285     ///
286     /// [`PathPersistError`]: struct.PathPersistError.html
persist_noclobber<P: AsRef<Path>>( mut self, new_path: P, ) -> Result<(), PathPersistError>287     pub fn persist_noclobber<P: AsRef<Path>>(
288         mut self,
289         new_path: P,
290     ) -> Result<(), PathPersistError> {
291         match imp::persist(&self.path, new_path.as_ref(), false) {
292             Ok(_) => {
293                 // Don't drop `self`. We don't want to try deleting the old
294                 // temporary file path. (It'll fail, but the failure is never
295                 // seen.)
296                 self.path = PathBuf::new().into_boxed_path();
297                 mem::forget(self);
298                 Ok(())
299             }
300             Err(e) => Err(PathPersistError {
301                 error: e,
302                 path: self,
303             }),
304         }
305     }
306 
307     /// Keep the temporary file from being deleted. This function will turn the
308     /// temporary file into a non-temporary file without moving it.
309     ///
310     ///
311     /// # Errors
312     ///
313     /// On some platforms (e.g., Windows), we need to mark the file as
314     /// non-temporary. This operation could fail.
315     ///
316     /// # Examples
317     ///
318     /// ```no_run
319     /// # use std::io::{self, Write};
320     /// use tempfile::NamedTempFile;
321     ///
322     /// # fn main() {
323     /// #     if let Err(_) = run() {
324     /// #         ::std::process::exit(1);
325     /// #     }
326     /// # }
327     /// # fn run() -> Result<(), io::Error> {
328     /// let mut file = NamedTempFile::new()?;
329     /// writeln!(file, "Brian was here. Briefly.")?;
330     ///
331     /// let path = file.into_temp_path();
332     /// let path = path.keep()?;
333     /// # Ok(())
334     /// # }
335     /// ```
336     ///
337     /// [`PathPersistError`]: struct.PathPersistError.html
keep(mut self) -> Result<PathBuf, PathPersistError>338     pub fn keep(mut self) -> Result<PathBuf, PathPersistError> {
339         match imp::keep(&self.path) {
340             Ok(_) => {
341                 // Don't drop `self`. We don't want to try deleting the old
342                 // temporary file path. (It'll fail, but the failure is never
343                 // seen.)
344                 let path = mem::replace(&mut self.path, PathBuf::new().into_boxed_path());
345                 mem::forget(self);
346                 Ok(path.into())
347             }
348             Err(e) => Err(PathPersistError {
349                 error: e,
350                 path: self,
351             }),
352         }
353     }
354 
355     /// Create a new TempPath from an existing path. This can be done even if no
356     /// file exists at the given path.
357     ///
358     /// This is mostly useful for interacting with libraries and external
359     /// components that provide files to be consumed or expect a path with no
360     /// existing file to be given.
from_path(path: impl Into<PathBuf>) -> Self361     pub fn from_path(path: impl Into<PathBuf>) -> Self {
362         Self {
363             path: path.into().into_boxed_path(),
364         }
365     }
366 }
367 
368 impl fmt::Debug for TempPath {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result369     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
370         self.path.fmt(f)
371     }
372 }
373 
374 impl Drop for TempPath {
drop(&mut self)375     fn drop(&mut self) {
376         let _ = fs::remove_file(&self.path);
377     }
378 }
379 
380 impl Deref for TempPath {
381     type Target = Path;
382 
deref(&self) -> &Path383     fn deref(&self) -> &Path {
384         &self.path
385     }
386 }
387 
388 impl AsRef<Path> for TempPath {
as_ref(&self) -> &Path389     fn as_ref(&self) -> &Path {
390         &self.path
391     }
392 }
393 
394 impl AsRef<OsStr> for TempPath {
as_ref(&self) -> &OsStr395     fn as_ref(&self) -> &OsStr {
396         self.path.as_os_str()
397     }
398 }
399 
400 /// A named temporary file.
401 ///
402 /// The default constructor, [`NamedTempFile::new()`], creates files in
403 /// the location returned by [`std::env::temp_dir()`], but `NamedTempFile`
404 /// can be configured to manage a temporary file in any location
405 /// by constructing with [`NamedTempFile::new_in()`].
406 ///
407 /// # Security
408 ///
409 /// Most operating systems employ temporary file cleaners to delete old
410 /// temporary files. Unfortunately these temporary file cleaners don't always
411 /// reliably _detect_ whether the temporary file is still being used.
412 ///
413 /// Specifically, the following sequence of events can happen:
414 ///
415 /// 1. A user creates a temporary file with `NamedTempFile::new()`.
416 /// 2. Time passes.
417 /// 3. The temporary file cleaner deletes (unlinks) the temporary file from the
418 ///    filesystem.
419 /// 4. Some other program creates a new file to replace this deleted temporary
420 ///    file.
421 /// 5. The user tries to re-open the temporary file (in the same program or in a
422 ///    different program) by path. Unfortunately, they'll end up opening the
423 ///    file created by the other program, not the original file.
424 ///
425 /// ## Operating System Specific Concerns
426 ///
427 /// The behavior of temporary files and temporary file cleaners differ by
428 /// operating system.
429 ///
430 /// ### Windows
431 ///
432 /// On Windows, open files _can't_ be deleted. This removes most of the concerns
433 /// around temporary file cleaners.
434 ///
435 /// Furthermore, temporary files are, by default, created in per-user temporary
436 /// file directories so only an application running as the same user would be
437 /// able to interfere (which they could do anyways). However, an application
438 /// running as the same user can still _accidentally_ re-create deleted
439 /// temporary files if the number of random bytes in the temporary file name is
440 /// too small.
441 ///
442 /// So, the only real concern on Windows is:
443 ///
444 /// 1. Opening a named temporary file in a world-writable directory.
445 /// 2. Using the `into_temp_path()` and/or `into_parts()` APIs to close the file
446 ///    handle without deleting the underlying file.
447 /// 3. Continuing to use the file by path.
448 ///
449 /// ### UNIX
450 ///
451 /// Unlike on Windows, UNIX (and UNIX like) systems allow open files to be
452 /// "unlinked" (deleted).
453 ///
454 /// #### MacOS
455 ///
456 /// Like on Windows, temporary files are created in per-user temporary file
457 /// directories by default so calling `NamedTempFile::new()` should be
458 /// relatively safe.
459 ///
460 /// #### Linux
461 ///
462 /// Unfortunately, most _Linux_ distributions don't create per-user temporary
463 /// file directories. Worse, systemd's tmpfiles daemon (a common temporary file
464 /// cleaner) will happily remove open temporary files if they haven't been
465 /// modified within the last 10 days.
466 ///
467 /// # Resource Leaking
468 ///
469 /// If the program exits before the `NamedTempFile` destructor is
470 /// run, such as via [`std::process::exit()`], by segfaulting, or by
471 /// receiving a signal like `SIGINT`, then the temporary file
472 /// will not be deleted.
473 ///
474 /// Use the [`tempfile()`] function unless you absolutely need a named file.
475 ///
476 /// [`tempfile()`]: fn.tempfile.html
477 /// [`NamedTempFile::new()`]: #method.new
478 /// [`NamedTempFile::new_in()`]: #method.new_in
479 /// [`std::env::temp_dir()`]: https://doc.rust-lang.org/std/env/fn.temp_dir.html
480 /// [`std::process::exit()`]: http://doc.rust-lang.org/std/process/fn.exit.html
481 pub struct NamedTempFile {
482     path: TempPath,
483     file: File,
484 }
485 
486 impl fmt::Debug for NamedTempFile {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result487     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
488         write!(f, "NamedTempFile({:?})", self.path)
489     }
490 }
491 
492 impl AsRef<Path> for NamedTempFile {
493     #[inline]
as_ref(&self) -> &Path494     fn as_ref(&self) -> &Path {
495         self.path()
496     }
497 }
498 
499 /// Error returned when persisting a temporary file fails.
500 #[derive(Debug)]
501 pub struct PersistError {
502     /// The underlying IO error.
503     pub error: io::Error,
504     /// The temporary file that couldn't be persisted.
505     pub file: NamedTempFile,
506 }
507 
508 impl From<PersistError> for io::Error {
509     #[inline]
from(error: PersistError) -> io::Error510     fn from(error: PersistError) -> io::Error {
511         error.error
512     }
513 }
514 
515 impl From<PersistError> for NamedTempFile {
516     #[inline]
from(error: PersistError) -> NamedTempFile517     fn from(error: PersistError) -> NamedTempFile {
518         error.file
519     }
520 }
521 
522 impl fmt::Display for PersistError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result523     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
524         write!(f, "failed to persist temporary file: {}", self.error)
525     }
526 }
527 
528 impl error::Error for PersistError {
source(&self) -> Option<&(dyn error::Error + 'static)>529     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
530         Some(&self.error)
531     }
532 }
533 
534 impl NamedTempFile {
535     /// Create a new named temporary file.
536     ///
537     /// See [`Builder`] for more configuration.
538     ///
539     /// # Security
540     ///
541     /// This will create a temporary file in the default temporary file
542     /// directory (platform dependent). This has security implications on many
543     /// platforms so please read the security section of this type's
544     /// documentation.
545     ///
546     /// Reasons to use this method:
547     ///
548     ///   1. The file has a short lifetime and your temporary file cleaner is
549     ///      sane (doesn't delete recently accessed files).
550     ///
551     ///   2. You trust every user on your system (i.e. you are the only user).
552     ///
553     ///   3. You have disabled your system's temporary file cleaner or verified
554     ///      that your system doesn't have a temporary file cleaner.
555     ///
556     /// Reasons not to use this method:
557     ///
558     ///   1. You'll fix it later. No you won't.
559     ///
560     ///   2. You don't care about the security of the temporary file. If none of
561     ///      the "reasons to use this method" apply, referring to a temporary
562     ///      file by name may allow an attacker to create/overwrite your
563     ///      non-temporary files. There are exceptions but if you don't already
564     ///      know them, don't use this method.
565     ///
566     /// # Errors
567     ///
568     /// If the file can not be created, `Err` is returned.
569     ///
570     /// # Examples
571     ///
572     /// Create a named temporary file and write some data to it:
573     ///
574     /// ```no_run
575     /// # use std::io::{self, Write};
576     /// use tempfile::NamedTempFile;
577     ///
578     /// # fn main() {
579     /// #     if let Err(_) = run() {
580     /// #         ::std::process::exit(1);
581     /// #     }
582     /// # }
583     /// # fn run() -> Result<(), ::std::io::Error> {
584     /// let mut file = NamedTempFile::new()?;
585     ///
586     /// writeln!(file, "Brian was here. Briefly.")?;
587     /// # Ok(())
588     /// # }
589     /// ```
590     ///
591     /// [`Builder`]: struct.Builder.html
new() -> io::Result<NamedTempFile>592     pub fn new() -> io::Result<NamedTempFile> {
593         Builder::new().tempfile()
594     }
595 
596     /// Create a new named temporary file in the specified directory.
597     ///
598     /// See [`NamedTempFile::new()`] for details.
599     ///
600     /// [`NamedTempFile::new()`]: #method.new
new_in<P: AsRef<Path>>(dir: P) -> io::Result<NamedTempFile>601     pub fn new_in<P: AsRef<Path>>(dir: P) -> io::Result<NamedTempFile> {
602         Builder::new().tempfile_in(dir)
603     }
604 
605     /// Get the temporary file's path.
606     ///
607     /// # Security
608     ///
609     /// Referring to a temporary file's path may not be secure in all cases.
610     /// Please read the security section on the top level documentation of this
611     /// type for details.
612     ///
613     /// # Examples
614     ///
615     /// ```no_run
616     /// # use std::io::{self, Write};
617     /// use tempfile::NamedTempFile;
618     ///
619     /// # fn main() {
620     /// #     if let Err(_) = run() {
621     /// #         ::std::process::exit(1);
622     /// #     }
623     /// # }
624     /// # fn run() -> Result<(), ::std::io::Error> {
625     /// let file = NamedTempFile::new()?;
626     ///
627     /// println!("{:?}", file.path());
628     /// # Ok(())
629     /// # }
630     /// ```
631     #[inline]
path(&self) -> &Path632     pub fn path(&self) -> &Path {
633         &self.path
634     }
635 
636     /// Close and remove the temporary file.
637     ///
638     /// Use this if you want to detect errors in deleting the file.
639     ///
640     /// # Errors
641     ///
642     /// If the file cannot be deleted, `Err` is returned.
643     ///
644     /// # Examples
645     ///
646     /// ```no_run
647     /// # use std::io;
648     /// use tempfile::NamedTempFile;
649     ///
650     /// # fn main() {
651     /// #     if let Err(_) = run() {
652     /// #         ::std::process::exit(1);
653     /// #     }
654     /// # }
655     /// # fn run() -> Result<(), io::Error> {
656     /// let file = NamedTempFile::new()?;
657     ///
658     /// // By closing the `NamedTempFile` explicitly, we can check that it has
659     /// // been deleted successfully. If we don't close it explicitly,
660     /// // the file will still be deleted when `file` goes out
661     /// // of scope, but we won't know whether deleting the file
662     /// // succeeded.
663     /// file.close()?;
664     /// # Ok(())
665     /// # }
666     /// ```
close(self) -> io::Result<()>667     pub fn close(self) -> io::Result<()> {
668         let NamedTempFile { path, .. } = self;
669         path.close()
670     }
671 
672     /// Persist the temporary file at the target path.
673     ///
674     /// If a file exists at the target path, persist will atomically replace it.
675     /// If this method fails, it will return `self` in the resulting
676     /// [`PersistError`].
677     ///
678     /// Note: Temporary files cannot be persisted across filesystems. Also
679     /// neither the file contents nor the containing directory are
680     /// synchronized, so the update may not yet have reached the disk when
681     /// `persist` returns.
682     ///
683     /// # Security
684     ///
685     /// This method persists the temporary file using its path and may not be
686     /// secure in the in all cases. Please read the security section on the top
687     /// level documentation of this type for details.
688     ///
689     /// # Errors
690     ///
691     /// If the file cannot be moved to the new location, `Err` is returned.
692     ///
693     /// # Examples
694     ///
695     /// ```no_run
696     /// # use std::io::{self, Write};
697     /// use tempfile::NamedTempFile;
698     ///
699     /// # fn main() {
700     /// #     if let Err(_) = run() {
701     /// #         ::std::process::exit(1);
702     /// #     }
703     /// # }
704     /// # fn run() -> Result<(), io::Error> {
705     /// let file = NamedTempFile::new()?;
706     ///
707     /// let mut persisted_file = file.persist("./saved_file.txt")?;
708     /// writeln!(persisted_file, "Brian was here. Briefly.")?;
709     /// # Ok(())
710     /// # }
711     /// ```
712     ///
713     /// [`PersistError`]: struct.PersistError.html
persist<P: AsRef<Path>>(self, new_path: P) -> Result<File, PersistError>714     pub fn persist<P: AsRef<Path>>(self, new_path: P) -> Result<File, PersistError> {
715         let NamedTempFile { path, file } = self;
716         match path.persist(new_path) {
717             Ok(_) => Ok(file),
718             Err(err) => {
719                 let PathPersistError { error, path } = err;
720                 Err(PersistError {
721                     file: NamedTempFile { path, file },
722                     error,
723                 })
724             }
725         }
726     }
727 
728     /// Persist the temporary file at the target path if and only if no file exists there.
729     ///
730     /// If a file exists at the target path, fail. If this method fails, it will
731     /// return `self` in the resulting PersistError.
732     ///
733     /// Note: Temporary files cannot be persisted across filesystems. Also Note:
734     /// This method is not atomic. It can leave the original link to the
735     /// temporary file behind.
736     ///
737     /// # Security
738     ///
739     /// This method persists the temporary file using its path and may not be
740     /// secure in the in all cases. Please read the security section on the top
741     /// level documentation of this type for details.
742     ///
743     /// # Errors
744     ///
745     /// If the file cannot be moved to the new location or a file already exists there,
746     /// `Err` is returned.
747     ///
748     /// # Examples
749     ///
750     /// ```no_run
751     /// # use std::io::{self, Write};
752     /// use tempfile::NamedTempFile;
753     ///
754     /// # fn main() {
755     /// #     if let Err(_) = run() {
756     /// #         ::std::process::exit(1);
757     /// #     }
758     /// # }
759     /// # fn run() -> Result<(), io::Error> {
760     /// let file = NamedTempFile::new()?;
761     ///
762     /// let mut persisted_file = file.persist_noclobber("./saved_file.txt")?;
763     /// writeln!(persisted_file, "Brian was here. Briefly.")?;
764     /// # Ok(())
765     /// # }
766     /// ```
persist_noclobber<P: AsRef<Path>>(self, new_path: P) -> Result<File, PersistError>767     pub fn persist_noclobber<P: AsRef<Path>>(self, new_path: P) -> Result<File, PersistError> {
768         let NamedTempFile { path, file } = self;
769         match path.persist_noclobber(new_path) {
770             Ok(_) => Ok(file),
771             Err(err) => {
772                 let PathPersistError { error, path } = err;
773                 Err(PersistError {
774                     file: NamedTempFile { path, file },
775                     error,
776                 })
777             }
778         }
779     }
780 
781     /// Keep the temporary file from being deleted. This function will turn the
782     /// temporary file into a non-temporary file without moving it.
783     ///
784     ///
785     /// # Errors
786     ///
787     /// On some platforms (e.g., Windows), we need to mark the file as
788     /// non-temporary. This operation could fail.
789     ///
790     /// # Examples
791     ///
792     /// ```no_run
793     /// # use std::io::{self, Write};
794     /// use tempfile::NamedTempFile;
795     ///
796     /// # fn main() {
797     /// #     if let Err(_) = run() {
798     /// #         ::std::process::exit(1);
799     /// #     }
800     /// # }
801     /// # fn run() -> Result<(), io::Error> {
802     /// let mut file = NamedTempFile::new()?;
803     /// writeln!(file, "Brian was here. Briefly.")?;
804     ///
805     /// let (file, path) = file.keep()?;
806     /// # Ok(())
807     /// # }
808     /// ```
809     ///
810     /// [`PathPersistError`]: struct.PathPersistError.html
keep(self) -> Result<(File, PathBuf), PersistError>811     pub fn keep(self) -> Result<(File, PathBuf), PersistError> {
812         let (file, path) = (self.file, self.path);
813         match path.keep() {
814             Ok(path) => Ok((file, path)),
815             Err(PathPersistError { error, path }) => Err(PersistError {
816                 file: NamedTempFile { path, file },
817                 error,
818             }),
819         }
820     }
821 
822     /// Securely reopen the temporary file.
823     ///
824     /// This function is useful when you need multiple independent handles to
825     /// the same file. It's perfectly fine to drop the original `NamedTempFile`
826     /// while holding on to `File`s returned by this function; the `File`s will
827     /// remain usable. However, they may not be nameable.
828     ///
829     /// # Errors
830     ///
831     /// If the file cannot be reopened, `Err` is returned.
832     ///
833     /// # Security
834     ///
835     /// Unlike `File::open(my_temp_file.path())`, `NamedTempFile::reopen()`
836     /// guarantees that the re-opened file is the _same_ file, even in the
837     /// presence of pathological temporary file cleaners.
838     ///
839     /// # Examples
840     ///
841     /// ```no_run
842     /// # use std::io;
843     /// use tempfile::NamedTempFile;
844     ///
845     /// # fn main() {
846     /// #     if let Err(_) = run() {
847     /// #         ::std::process::exit(1);
848     /// #     }
849     /// # }
850     /// # fn run() -> Result<(), io::Error> {
851     /// let file = NamedTempFile::new()?;
852     ///
853     /// let another_handle = file.reopen()?;
854     /// # Ok(())
855     /// # }
856     /// ```
reopen(&self) -> io::Result<File>857     pub fn reopen(&self) -> io::Result<File> {
858         imp::reopen(self.as_file(), NamedTempFile::path(self))
859             .with_err_path(|| NamedTempFile::path(self))
860     }
861 
862     /// Get a reference to the underlying file.
as_file(&self) -> &File863     pub fn as_file(&self) -> &File {
864         &self.file
865     }
866 
867     /// Get a mutable reference to the underlying file.
as_file_mut(&mut self) -> &mut File868     pub fn as_file_mut(&mut self) -> &mut File {
869         &mut self.file
870     }
871 
872     /// Convert the temporary file into a `std::fs::File`.
873     ///
874     /// The inner file will be deleted.
into_file(self) -> File875     pub fn into_file(self) -> File {
876         self.file
877     }
878 
879     /// Closes the file, leaving only the temporary file path.
880     ///
881     /// This is useful when another process must be able to open the temporary
882     /// file.
into_temp_path(self) -> TempPath883     pub fn into_temp_path(self) -> TempPath {
884         self.path
885     }
886 
887     /// Converts the named temporary file into its constituent parts.
888     ///
889     /// Note: When the path is dropped, the file is deleted but the file handle
890     /// is still usable.
into_parts(self) -> (File, TempPath)891     pub fn into_parts(self) -> (File, TempPath) {
892         (self.file, self.path)
893     }
894 }
895 
896 impl Read for NamedTempFile {
read(&mut self, buf: &mut [u8]) -> io::Result<usize>897     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
898         self.as_file_mut().read(buf).with_err_path(|| self.path())
899     }
900 }
901 
902 impl<'a> Read for &'a NamedTempFile {
read(&mut self, buf: &mut [u8]) -> io::Result<usize>903     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
904         self.as_file().read(buf).with_err_path(|| self.path())
905     }
906 }
907 
908 impl Write for NamedTempFile {
write(&mut self, buf: &[u8]) -> io::Result<usize>909     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
910         self.as_file_mut().write(buf).with_err_path(|| self.path())
911     }
912     #[inline]
flush(&mut self) -> io::Result<()>913     fn flush(&mut self) -> io::Result<()> {
914         self.as_file_mut().flush().with_err_path(|| self.path())
915     }
916 }
917 
918 impl<'a> Write for &'a NamedTempFile {
write(&mut self, buf: &[u8]) -> io::Result<usize>919     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
920         self.as_file().write(buf).with_err_path(|| self.path())
921     }
922     #[inline]
flush(&mut self) -> io::Result<()>923     fn flush(&mut self) -> io::Result<()> {
924         self.as_file().flush().with_err_path(|| self.path())
925     }
926 }
927 
928 impl Seek for NamedTempFile {
seek(&mut self, pos: SeekFrom) -> io::Result<u64>929     fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
930         self.as_file_mut().seek(pos).with_err_path(|| self.path())
931     }
932 }
933 
934 impl<'a> Seek for &'a NamedTempFile {
seek(&mut self, pos: SeekFrom) -> io::Result<u64>935     fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
936         self.as_file().seek(pos).with_err_path(|| self.path())
937     }
938 }
939 
940 #[cfg(unix)]
941 impl std::os::unix::io::AsRawFd for NamedTempFile {
942     #[inline]
as_raw_fd(&self) -> std::os::unix::io::RawFd943     fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
944         self.as_file().as_raw_fd()
945     }
946 }
947 
948 #[cfg(windows)]
949 impl std::os::windows::io::AsRawHandle for NamedTempFile {
950     #[inline]
as_raw_handle(&self) -> std::os::windows::io::RawHandle951     fn as_raw_handle(&self) -> std::os::windows::io::RawHandle {
952         self.as_file().as_raw_handle()
953     }
954 }
955 
create_named( mut path: PathBuf, open_options: &mut OpenOptions, ) -> io::Result<NamedTempFile>956 pub(crate) fn create_named(
957     mut path: PathBuf,
958     open_options: &mut OpenOptions,
959 ) -> io::Result<NamedTempFile> {
960     // Make the path absolute. Otherwise, changing directories could cause us to
961     // delete the wrong file.
962     if !path.is_absolute() {
963         path = env::current_dir()?.join(path)
964     }
965     imp::create_named(&path, open_options)
966         .with_err_path(|| path.clone())
967         .map(|file| NamedTempFile {
968             path: TempPath {
969                 path: path.into_boxed_path(),
970             },
971             file,
972         })
973 }
974