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