1 //! Temporary files and directories.
2 //!
3 //! - Use the [`tempfile()`] function for temporary files
4 //! - Use the [`tempdir()`] function for temporary directories.
5 //!
6 //! # Design
7 //!
8 //! This crate provides several approaches to creating temporary files and directories.
9 //! [`tempfile()`] relies on the OS to remove the temporary file once the last handle is closed.
10 //! [`TempDir`] and [`NamedTempFile`] both rely on Rust destructors for cleanup.
11 //!
12 //! When choosing between the temporary file variants, prefer `tempfile`
13 //! unless you either need to know the file's path or to be able to persist it.
14 //!
15 //! ## Resource Leaking
16 //!
17 //! `tempfile` will (almost) never fail to cleanup temporary resources. However `TempDir` and `NamedTempFile` will
18 //! fail if their destructors don't run. This is because `tempfile` relies on the OS to cleanup the
19 //! underlying file, while `TempDir` and `NamedTempFile` rely on rust destructors to do so.
20 //! Destructors may fail to run if the process exits through an unhandled signal interrupt (like `SIGINT`),
21 //! or if the instance is declared statically (like with [`lazy_static`]), among other possible
22 //! reasons.
23 //!
24 //! ## Security
25 //!
26 //! In the presence of pathological temporary file cleaner, relying on file paths is unsafe because
27 //! a temporary file cleaner could delete the temporary file which an attacker could then replace.
28 //!
29 //! `tempfile` doesn't rely on file paths so this isn't an issue. However, `NamedTempFile` does
30 //! rely on file paths for _some_ operations. See the security documentation on
31 //! the `NamedTempFile` type for more information.
32 //!
33 //! ## Early drop pitfall
34 //!
35 //! Because `TempDir` and `NamedTempFile` rely on their destructors for cleanup, this can lead
36 //! to an unexpected early removal of the directory/file, usually when working with APIs which are
37 //! generic over `AsRef<Path>`. Consider the following example:
38 //!
39 //! ```no_run
40 //! use tempfile::tempdir;
41 //! use std::process::Command;
42 //!
43 //! // Create a directory inside of `env::temp_dir()`.
44 //! let temp_dir = tempdir()?;
45 //!
46 //! // Spawn the `touch` command inside the temporary directory and collect the exit status
47 //! // Note that `temp_dir` is **not** moved into `current_dir`, but passed as a reference
48 //! let exit_status = Command::new("touch").arg("tmp").current_dir(&temp_dir).status()?;
49 //! assert!(exit_status.success());
50 //!
51 //! # Ok::<(), std::io::Error>(())
52 //! ```
53 //!
54 //! This works because a reference to `temp_dir` is passed to `current_dir`, resulting in the
55 //! destructor of `temp_dir` being run after the `Command` has finished execution. Moving the
56 //! `TempDir` into the `current_dir` call would result in the `TempDir` being converted into
57 //! an internal representation, with the original value being dropped and the directory thus
58 //! being deleted, before the command can be executed.
59 //!
60 //! The `touch` command would fail with an `No such file or directory` error.
61 //!
62 //! ## Examples
63 //!
64 //! Create a temporary file and write some data into it:
65 //!
66 //! ```
67 //! use tempfile::tempfile;
68 //! use std::io::Write;
69 //!
70 //! // Create a file inside of `env::temp_dir()`.
71 //! let mut file = tempfile()?;
72 //!
73 //! writeln!(file, "Brian was here. Briefly.")?;
74 //! # Ok::<(), std::io::Error>(())
75 //! ```
76 //!
77 //! Create a named temporary file and open an independent file handle:
78 //!
79 //! ```
80 //! use tempfile::NamedTempFile;
81 //! use std::io::{Write, Read};
82 //!
83 //! let text = "Brian was here. Briefly.";
84 //!
85 //! // Create a file inside of `env::temp_dir()`.
86 //! let mut file1 = NamedTempFile::new()?;
87 //!
88 //! // Re-open it.
89 //! let mut file2 = file1.reopen()?;
90 //!
91 //! // Write some test data to the first handle.
92 //! file1.write_all(text.as_bytes())?;
93 //!
94 //! // Read the test data using the second handle.
95 //! let mut buf = String::new();
96 //! file2.read_to_string(&mut buf)?;
97 //! assert_eq!(buf, text);
98 //! # Ok::<(), std::io::Error>(())
99 //! ```
100 //!
101 //! Create a temporary directory and add a file to it:
102 //!
103 //! ```
104 //! use tempfile::tempdir;
105 //! use std::fs::File;
106 //! use std::io::Write;
107 //!
108 //! // Create a directory inside of `env::temp_dir()`.
109 //! let dir = tempdir()?;
110 //!
111 //! let file_path = dir.path().join("my-temporary-note.txt");
112 //! let mut file = File::create(file_path)?;
113 //! writeln!(file, "Brian was here. Briefly.")?;
114 //!
115 //! // By closing the `TempDir` explicitly, we can check that it has
116 //! // been deleted successfully. If we don't close it explicitly,
117 //! // the directory will still be deleted when `dir` goes out
118 //! // of scope, but we won't know whether deleting the directory
119 //! // succeeded.
120 //! drop(file);
121 //! dir.close()?;
122 //! # Ok::<(), std::io::Error>(())
123 //! ```
124 //!
125 //! [`tempfile()`]: fn.tempfile.html
126 //! [`tempdir()`]: fn.tempdir.html
127 //! [`TempDir`]: struct.TempDir.html
128 //! [`NamedTempFile`]: struct.NamedTempFile.html
129 //! [`lazy_static`]: https://github.com/rust-lang-nursery/lazy-static.rs/issues/62
130 
131 #![doc(
132     html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
133     html_favicon_url = "https://www.rust-lang.org/favicon.ico",
134     html_root_url = "https://docs.rs/tempfile/latest"
135 )]
136 #![cfg_attr(test, deny(warnings))]
137 #![deny(rust_2018_idioms)]
138 #![allow(clippy::redundant_field_names)]
139 #![cfg_attr(all(feature = "nightly", target_os = "wasi"), feature(wasi_ext))]
140 
141 #[cfg(doctest)]
142 doc_comment::doctest!("../README.md");
143 
144 const NUM_RETRIES: u32 = 1 << 31;
145 const NUM_RAND_CHARS: usize = 6;
146 
147 use std::ffi::OsStr;
148 use std::fs::OpenOptions;
149 use std::io;
150 use std::path::Path;
151 
152 mod dir;
153 mod error;
154 mod file;
155 mod spooled;
156 mod util;
157 
158 pub mod env;
159 
160 pub use crate::dir::{tempdir, tempdir_in, TempDir};
161 pub use crate::file::{
162     tempfile, tempfile_in, NamedTempFile, PathPersistError, PersistError, TempPath,
163 };
164 pub use crate::spooled::{spooled_tempfile, SpooledTempFile};
165 
166 /// Create a new temporary file or directory with custom parameters.
167 #[derive(Debug, Clone, Eq, PartialEq)]
168 pub struct Builder<'a, 'b> {
169     random_len: usize,
170     prefix: &'a OsStr,
171     suffix: &'b OsStr,
172     append: bool,
173     permissions: Option<std::fs::Permissions>,
174     keep: bool,
175 }
176 
177 impl<'a, 'b> Default for Builder<'a, 'b> {
default() -> Self178     fn default() -> Self {
179         Builder {
180             random_len: crate::NUM_RAND_CHARS,
181             prefix: OsStr::new(".tmp"),
182             suffix: OsStr::new(""),
183             append: false,
184             permissions: None,
185             keep: false,
186         }
187     }
188 }
189 
190 impl<'a, 'b> Builder<'a, 'b> {
191     /// Create a new `Builder`.
192     ///
193     /// # Examples
194     ///
195     /// Create a named temporary file and write some data into it:
196     ///
197     /// ```
198     /// use std::ffi::OsStr;
199     /// use tempfile::Builder;
200     ///
201     /// let named_tempfile = Builder::new()
202     ///     .prefix("my-temporary-note")
203     ///     .suffix(".txt")
204     ///     .rand_bytes(5)
205     ///     .tempfile()?;
206     ///
207     /// let name = named_tempfile
208     ///     .path()
209     ///     .file_name().and_then(OsStr::to_str);
210     ///
211     /// if let Some(name) = name {
212     ///     assert!(name.starts_with("my-temporary-note"));
213     ///     assert!(name.ends_with(".txt"));
214     ///     assert_eq!(name.len(), "my-temporary-note.txt".len() + 5);
215     /// }
216     /// # Ok::<(), std::io::Error>(())
217     /// ```
218     ///
219     /// Create a temporary directory and add a file to it:
220     ///
221     /// ```
222     /// use std::io::Write;
223     /// use std::fs::File;
224     /// use std::ffi::OsStr;
225     /// use tempfile::Builder;
226     ///
227     /// let dir = Builder::new()
228     ///     .prefix("my-temporary-dir")
229     ///     .rand_bytes(5)
230     ///     .tempdir()?;
231     ///
232     /// let file_path = dir.path().join("my-temporary-note.txt");
233     /// let mut file = File::create(file_path)?;
234     /// writeln!(file, "Brian was here. Briefly.")?;
235     ///
236     /// // By closing the `TempDir` explicitly, we can check that it has
237     /// // been deleted successfully. If we don't close it explicitly,
238     /// // the directory will still be deleted when `dir` goes out
239     /// // of scope, but we won't know whether deleting the directory
240     /// // succeeded.
241     /// drop(file);
242     /// dir.close()?;
243     /// # Ok::<(), std::io::Error>(())
244     /// ```
245     ///
246     /// Create a temporary directory with a chosen prefix under a chosen folder:
247     ///
248     /// ```no_run
249     /// use tempfile::Builder;
250     ///
251     /// let dir = Builder::new()
252     ///     .prefix("my-temporary-dir")
253     ///     .tempdir_in("folder-with-tempdirs")?;
254     /// # Ok::<(), std::io::Error>(())
255     /// ```
256     #[must_use]
new() -> Self257     pub fn new() -> Self {
258         Self::default()
259     }
260 
261     /// Set a custom filename prefix.
262     ///
263     /// Path separators are legal but not advisable.
264     /// Default: `.tmp`.
265     ///
266     /// # Examples
267     ///
268     /// ```
269     /// use tempfile::Builder;
270     ///
271     /// let named_tempfile = Builder::new()
272     ///     .prefix("my-temporary-note")
273     ///     .tempfile()?;
274     /// # Ok::<(), std::io::Error>(())
275     /// ```
prefix<S: AsRef<OsStr> + ?Sized>(&mut self, prefix: &'a S) -> &mut Self276     pub fn prefix<S: AsRef<OsStr> + ?Sized>(&mut self, prefix: &'a S) -> &mut Self {
277         self.prefix = prefix.as_ref();
278         self
279     }
280 
281     /// Set a custom filename suffix.
282     ///
283     /// Path separators are legal but not advisable.
284     /// Default: empty.
285     ///
286     /// # Examples
287     ///
288     /// ```
289     /// use tempfile::Builder;
290     ///
291     /// let named_tempfile = Builder::new()
292     ///     .suffix(".txt")
293     ///     .tempfile()?;
294     /// # Ok::<(), std::io::Error>(())
295     /// ```
suffix<S: AsRef<OsStr> + ?Sized>(&mut self, suffix: &'b S) -> &mut Self296     pub fn suffix<S: AsRef<OsStr> + ?Sized>(&mut self, suffix: &'b S) -> &mut Self {
297         self.suffix = suffix.as_ref();
298         self
299     }
300 
301     /// Set the number of random bytes.
302     ///
303     /// Default: `6`.
304     ///
305     /// # Examples
306     ///
307     /// ```
308     /// use tempfile::Builder;
309     ///
310     /// let named_tempfile = Builder::new()
311     ///     .rand_bytes(5)
312     ///     .tempfile()?;
313     /// # Ok::<(), std::io::Error>(())
314     /// ```
rand_bytes(&mut self, rand: usize) -> &mut Self315     pub fn rand_bytes(&mut self, rand: usize) -> &mut Self {
316         self.random_len = rand;
317         self
318     }
319 
320     /// Set the file to be opened in append mode.
321     ///
322     /// Default: `false`.
323     ///
324     /// # Examples
325     ///
326     /// ```
327     /// use tempfile::Builder;
328     ///
329     /// let named_tempfile = Builder::new()
330     ///     .append(true)
331     ///     .tempfile()?;
332     /// # Ok::<(), std::io::Error>(())
333     /// ```
append(&mut self, append: bool) -> &mut Self334     pub fn append(&mut self, append: bool) -> &mut Self {
335         self.append = append;
336         self
337     }
338 
339     /// The permissions to create the tempfile or [tempdir](Self::tempdir) with.
340     /// This allows to them differ from the default mode of `0o600` on Unix.
341     ///
342     /// # Security
343     ///
344     /// By default, the permissions of tempfiles on unix are set for it to be
345     /// readable and writable by the owner only, yielding the greatest amount
346     /// of security.
347     /// As this method allows to widen the permissions, security would be
348     /// reduced in such cases.
349     ///
350     /// # Platform Notes
351     /// ## Unix
352     ///
353     /// The actual permission bits set on the tempfile or tempdir will be affected by the
354     /// `umask` applied by the underlying syscall.
355     ///
356     ///
357     /// ## Windows and others
358     ///
359     /// This setting is unsupported and trying to set a file or directory read-only
360     /// will cause an error to be returned..
361     ///
362     /// # Examples
363     ///
364     /// Create a named temporary file that is world-readable.
365     ///
366     /// ```
367     /// # #[cfg(unix)]
368     /// # {
369     /// use tempfile::Builder;
370     /// use std::os::unix::fs::PermissionsExt;
371     ///
372     /// let all_read_write = std::fs::Permissions::from_mode(0o666);
373     /// let tempfile = Builder::new().permissions(all_read_write).tempfile()?;
374     /// let actual_permissions = tempfile.path().metadata()?.permissions();
375     /// assert_ne!(
376     ///     actual_permissions.mode() & !0o170000,
377     ///     0o600,
378     ///     "we get broader permissions than the default despite umask"
379     /// );
380     /// # }
381     /// # Ok::<(), std::io::Error>(())
382     /// ```
383     ///
384     /// Create a named temporary directory that is restricted to the owner.
385     ///
386     /// ```
387     /// # #[cfg(unix)]
388     /// # {
389     /// use tempfile::Builder;
390     /// use std::os::unix::fs::PermissionsExt;
391     ///
392     /// let owner_rwx = std::fs::Permissions::from_mode(0o700);
393     /// let tempdir = Builder::new().permissions(owner_rwx).tempdir()?;
394     /// let actual_permissions = tempdir.path().metadata()?.permissions();
395     /// assert_eq!(
396     ///     actual_permissions.mode() & !0o170000,
397     ///     0o700,
398     ///     "we get the narrow permissions we asked for"
399     /// );
400     /// # }
401     /// # Ok::<(), std::io::Error>(())
402     /// ```
permissions(&mut self, permissions: std::fs::Permissions) -> &mut Self403     pub fn permissions(&mut self, permissions: std::fs::Permissions) -> &mut Self {
404         self.permissions = Some(permissions);
405         self
406     }
407 
408     /// Set the file/folder to be kept even when the [`NamedTempFile`]/[`TempDir`] goes out of
409     /// scope.
410     ///
411     /// By default, the file/folder is automatically cleaned up in the destructor of
412     /// [`NamedTempFile`]/[`TempDir`]. When `keep` is set to `true`, this behavior is supressed.
413     ///
414     /// # Examples
415     ///
416     /// ```
417     /// use tempfile::Builder;
418     ///
419     /// let named_tempfile = Builder::new()
420     ///     .keep(true)
421     ///     .tempfile()?;
422     /// # Ok::<(), std::io::Error>(())
423     /// ```
keep(&mut self, keep: bool) -> &mut Self424     pub fn keep(&mut self, keep: bool) -> &mut Self {
425         self.keep = keep;
426         self
427     }
428 
429     /// Create the named temporary file.
430     ///
431     /// # Security
432     ///
433     /// See [the security][security] docs on `NamedTempFile`.
434     ///
435     /// # Resource leaking
436     ///
437     /// See [the resource leaking][resource-leaking] docs on `NamedTempFile`.
438     ///
439     /// # Errors
440     ///
441     /// If the file cannot be created, `Err` is returned.
442     ///
443     /// # Examples
444     ///
445     /// ```
446     /// use tempfile::Builder;
447     ///
448     /// let tempfile = Builder::new().tempfile()?;
449     /// # Ok::<(), std::io::Error>(())
450     /// ```
451     ///
452     /// [security]: struct.NamedTempFile.html#security
453     /// [resource-leaking]: struct.NamedTempFile.html#resource-leaking
tempfile(&self) -> io::Result<NamedTempFile>454     pub fn tempfile(&self) -> io::Result<NamedTempFile> {
455         self.tempfile_in(env::temp_dir())
456     }
457 
458     /// Create the named temporary file in the specified directory.
459     ///
460     /// # Security
461     ///
462     /// See [the security][security] docs on `NamedTempFile`.
463     ///
464     /// # Resource leaking
465     ///
466     /// See [the resource leaking][resource-leaking] docs on `NamedTempFile`.
467     ///
468     /// # Errors
469     ///
470     /// If the file cannot be created, `Err` is returned.
471     ///
472     /// # Examples
473     ///
474     /// ```
475     /// use tempfile::Builder;
476     ///
477     /// let tempfile = Builder::new().tempfile_in("./")?;
478     /// # Ok::<(), std::io::Error>(())
479     /// ```
480     ///
481     /// [security]: struct.NamedTempFile.html#security
482     /// [resource-leaking]: struct.NamedTempFile.html#resource-leaking
tempfile_in<P: AsRef<Path>>(&self, dir: P) -> io::Result<NamedTempFile>483     pub fn tempfile_in<P: AsRef<Path>>(&self, dir: P) -> io::Result<NamedTempFile> {
484         util::create_helper(
485             dir.as_ref(),
486             self.prefix,
487             self.suffix,
488             self.random_len,
489             |path| {
490                 file::create_named(
491                     path,
492                     OpenOptions::new().append(self.append),
493                     self.permissions.as_ref(),
494                     self.keep,
495                 )
496             },
497         )
498     }
499 
500     /// Attempts to make a temporary directory inside of [`env::temp_dir()`] whose
501     /// name will have the prefix, `prefix`. The directory and
502     /// everything inside it will be automatically deleted once the
503     /// returned `TempDir` is destroyed.
504     ///
505     /// # Resource leaking
506     ///
507     /// See [the resource leaking][resource-leaking] docs on `TempDir`.
508     ///
509     /// # Errors
510     ///
511     /// If the directory can not be created, `Err` is returned.
512     ///
513     /// # Examples
514     ///
515     /// ```
516     /// use tempfile::Builder;
517     ///
518     /// let tmp_dir = Builder::new().tempdir()?;
519     /// # Ok::<(), std::io::Error>(())
520     /// ```
521     ///
522     /// [resource-leaking]: struct.TempDir.html#resource-leaking
tempdir(&self) -> io::Result<TempDir>523     pub fn tempdir(&self) -> io::Result<TempDir> {
524         self.tempdir_in(env::temp_dir())
525     }
526 
527     /// Attempts to make a temporary directory inside of `dir`.
528     /// The directory and everything inside it will be automatically
529     /// deleted once the returned `TempDir` is destroyed.
530     ///
531     /// # Resource leaking
532     ///
533     /// See [the resource leaking][resource-leaking] docs on `TempDir`.
534     ///
535     /// # Errors
536     ///
537     /// If the directory can not be created, `Err` is returned.
538     ///
539     /// # Examples
540     ///
541     /// ```
542     /// use tempfile::Builder;
543     ///
544     /// let tmp_dir = Builder::new().tempdir_in("./")?;
545     /// # Ok::<(), std::io::Error>(())
546     /// ```
547     ///
548     /// [resource-leaking]: struct.TempDir.html#resource-leaking
tempdir_in<P: AsRef<Path>>(&self, dir: P) -> io::Result<TempDir>549     pub fn tempdir_in<P: AsRef<Path>>(&self, dir: P) -> io::Result<TempDir> {
550         let storage;
551         let mut dir = dir.as_ref();
552         if !dir.is_absolute() {
553             let cur_dir = std::env::current_dir()?;
554             storage = cur_dir.join(dir);
555             dir = &storage;
556         }
557 
558         util::create_helper(dir, self.prefix, self.suffix, self.random_len, |path| {
559             dir::create(path, self.permissions.as_ref(), self.keep)
560         })
561     }
562 
563     /// Attempts to create a temporary file (or file-like object) using the
564     /// provided closure. The closure is passed a temporary file path and
565     /// returns an [`std::io::Result`]. The path provided to the closure will be
566     /// inside of [`env::temp_dir()`]. Use [`Builder::make_in`] to provide
567     /// a custom temporary directory. If the closure returns one of the
568     /// following errors, then another randomized file path is tried:
569     ///  - [`std::io::ErrorKind::AlreadyExists`]
570     ///  - [`std::io::ErrorKind::AddrInUse`]
571     ///
572     /// This can be helpful for taking full control over the file creation, but
573     /// leaving the temporary file path construction up to the library. This
574     /// also enables creating a temporary UNIX domain socket, since it is not
575     /// possible to bind to a socket that already exists.
576     ///
577     /// Note that [`Builder::append`] is ignored when using [`Builder::make`].
578     ///
579     /// # Security
580     ///
581     /// This has the same [security implications][security] as
582     /// [`NamedTempFile`], but with additional caveats. Specifically, it is up
583     /// to the closure to ensure that the file does not exist and that such a
584     /// check is *atomic*. Otherwise, a [time-of-check to time-of-use
585     /// bug][TOCTOU] could be introduced.
586     ///
587     /// For example, the following is **not** secure:
588     ///
589     /// ```
590     /// use std::fs::File;
591     /// use tempfile::Builder;
592     ///
593     /// // This is NOT secure!
594     /// let tempfile = Builder::new().make(|path| {
595     ///     if path.is_file() {
596     ///         return Err(std::io::ErrorKind::AlreadyExists.into());
597     ///     }
598     ///
599     ///     // Between the check above and the usage below, an attacker could
600     ///     // have replaced `path` with another file, which would get truncated
601     ///     // by `File::create`.
602     ///
603     ///     File::create(path)
604     /// })?;
605     /// # Ok::<(), std::io::Error>(())
606     /// ```
607     ///
608     /// Note that simply using [`std::fs::File::create`] alone is not correct
609     /// because it does not fail if the file already exists:
610     ///
611     /// ```
612     /// use tempfile::Builder;
613     /// use std::fs::File;
614     ///
615     /// // This could overwrite an existing file!
616     /// let tempfile = Builder::new().make(|path| File::create(path))?;
617     /// # Ok::<(), std::io::Error>(())
618     /// ```
619     /// For creating regular temporary files, use [`Builder::tempfile`] instead
620     /// to avoid these problems. This function is meant to enable more exotic
621     /// use-cases.
622     ///
623     /// # Resource leaking
624     ///
625     /// See [the resource leaking][resource-leaking] docs on `NamedTempFile`.
626     ///
627     /// # Errors
628     ///
629     /// If the closure returns any error besides
630     /// [`std::io::ErrorKind::AlreadyExists`] or
631     /// [`std::io::ErrorKind::AddrInUse`], then `Err` is returned.
632     ///
633     /// # Examples
634     /// ```
635     /// # #[cfg(unix)]
636     /// # {
637     /// use std::os::unix::net::UnixListener;
638     /// use tempfile::Builder;
639     ///
640     /// let tempsock = Builder::new().make(|path| UnixListener::bind(path))?;
641     /// # }
642     /// # Ok::<(), std::io::Error>(())
643     /// ```
644     ///
645     /// [TOCTOU]: https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use
646     /// [security]: struct.NamedTempFile.html#security
647     /// [resource-leaking]: struct.NamedTempFile.html#resource-leaking
make<F, R>(&self, f: F) -> io::Result<NamedTempFile<R>> where F: FnMut(&Path) -> io::Result<R>,648     pub fn make<F, R>(&self, f: F) -> io::Result<NamedTempFile<R>>
649     where
650         F: FnMut(&Path) -> io::Result<R>,
651     {
652         self.make_in(env::temp_dir(), f)
653     }
654 
655     /// This is the same as [`Builder::make`], except `dir` is used as the base
656     /// directory for the temporary file path.
657     ///
658     /// See [`Builder::make`] for more details and security implications.
659     ///
660     /// # Examples
661     /// ```
662     /// # #[cfg(unix)]
663     /// # {
664     /// use tempfile::Builder;
665     /// use std::os::unix::net::UnixListener;
666     ///
667     /// let tempsock = Builder::new().make_in("./", |path| UnixListener::bind(path))?;
668     /// # }
669     /// # Ok::<(), std::io::Error>(())
670     /// ```
make_in<F, R, P>(&self, dir: P, mut f: F) -> io::Result<NamedTempFile<R>> where F: FnMut(&Path) -> io::Result<R>, P: AsRef<Path>,671     pub fn make_in<F, R, P>(&self, dir: P, mut f: F) -> io::Result<NamedTempFile<R>>
672     where
673         F: FnMut(&Path) -> io::Result<R>,
674         P: AsRef<Path>,
675     {
676         util::create_helper(
677             dir.as_ref(),
678             self.prefix,
679             self.suffix,
680             self.random_len,
681             move |path| {
682                 Ok(NamedTempFile::from_parts(
683                     f(&path)?,
684                     TempPath::new(path, self.keep),
685                 ))
686             },
687         )
688     }
689 }
690