Coverage Report

Created: 2026-02-11 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/tempfile-3.25.0/src/lib.rs
Line
Count
Source
1
//! This is a library for creating temporary files and directories that are automatically deleted
2
//! when no longer referenced (i.e., on drop).
3
//!
4
//! - Use [`tempfile()`] when you need a real [`std::fs::File`] but don't need to refer to it
5
//!   by-path.
6
//! - Use [`NamedTempFile::new()`] when you need a _named_ temporary file that can be refered to its
7
//!   path.
8
//! - Use [`tempdir()`] when you need a temporary directory that will be recursively deleted on drop.
9
//! - Use [`spooled_tempfile()`] when you need an in-memory buffer that will ultimately be backed by
10
//!   a temporary file if it gets too large.
11
//!
12
//! # Design
13
//!
14
//! This crate provides several approaches to creating temporary files and directories.
15
//! [`tempfile()`] relies on the OS to remove the temporary file once the last handle is closed.
16
//! [`TempDir`] and [`NamedTempFile`] both rely on Rust destructors for cleanup.
17
//!
18
//! ## Resource Leaking
19
//!
20
//! `tempfile` will (almost) never fail to cleanup temporary resources. However `TempDir` and
21
//! `NamedTempFile` will fail if their destructors don't run. This is because `tempfile` relies on
22
//! the OS to cleanup the underlying file, while `TempDir` and `NamedTempFile` rely on rust
23
//! destructors to do so. Destructors may fail to run if the process exits through an unhandled
24
//! signal interrupt (like `SIGINT`), or if the instance is declared statically (like with
25
//! [`lazy_static`]), among other possible reasons.
26
//!
27
//! ## Unexpected File Deletion
28
//!
29
//! Most operating systems periodically clean up temporary files that haven't been accessed recently
30
//! (often on the order of multiple days). This issue does not affect unnamed temporary files but
31
//! can invalidate the paths associated with named temporary files on Unix-like systems because the
32
//! temporary file can be unlinked from the filesystem while still open and in-use. See the
33
//! [temporary file cleaner](#temporary-file-cleaners) section for more security implications.
34
//!
35
//! ## Security
36
//!
37
//! This section discusses security issues relevant to Unix-like operating systems that use shared
38
//! temporary directories by default. Importantly, it's not relevant for Windows or macOS as both
39
//! operating systems use private per-user temporary directories by default.
40
//!
41
//! Applications can mitigate the issues described below by using [`env::override_temp_dir`] to
42
//! change the default temporary directory but should do so if and only if default the temporary
43
//! directory ([`env::temp_dir`]) is unsuitable (is world readable, world writable, managed by a
44
//! temporary file cleaner, etc.).
45
//!
46
//! ### Temporary File Cleaners
47
//!
48
//! In the presence of pathological temporary file cleaner, relying on file paths is unsafe because
49
//! a temporary file cleaner could delete the temporary file which an attacker could then replace.
50
//!
51
//! This isn't an issue for [`tempfile`] as it doesn't rely on file paths. However, [`NamedTempFile`]
52
//! and temporary directories _do_ rely on file paths for _some_ operations. See the security
53
//! documentation on the [`NamedTempFile`] and the [`TempDir`] types for more information.
54
//!
55
//! Mitigation:
56
//!
57
//! - This is rarely an issue for short-lived files as temporary file cleaners usually only remove
58
//!   temporary files that haven't been modified or accessed within many (10-30) days.
59
//! - Very long lived temporary files should be placed in directories not managed by temporary file
60
//!   cleaners.
61
//!
62
//! ### Access Permissions
63
//!
64
//! Temporary _files_ created with this library are private by default on all operating systems.
65
//! However, temporary _directories_ are created with the default permissions and will therefore be
66
//! world-readable by default unless the user has changed their umask and/or default temporary
67
//! directory.
68
//!
69
//! ### Denial of Service
70
//!
71
//! If the file-name randomness ([`Builder::rand_bytes`]) is too small and/or this crate is built
72
//! without the `getrandom` feature, it may be possible for an attacker to predict the random file
73
//! names chosen by this library, preventing temporary file creation by creating temporary files
74
//! with these predicted file names. By default, this library mitigates this denial of service
75
//! attack by:
76
//!
77
//! 1. Defaulting to 6 random characters per temporary file forcing an attacker to create billions
78
//!    of files before random collisions are expected (at which point you probably have larger
79
//!    problems).
80
//! 2. Re-seeding the random filename generator from system randomness after 3 failed attempts to
81
//!    create temporary a file (when the `getrandom` feature is enabled as it is by default on all
82
//!    major platforms).
83
//!
84
//! ## Early drop pitfall
85
//!
86
//! Because `TempDir` and `NamedTempFile` rely on their destructors for cleanup, this can lead
87
//! to an unexpected early removal of the directory/file, usually when working with APIs which are
88
//! generic over `AsRef<Path>`. Consider the following example:
89
//!
90
//! ```no_run
91
//! use tempfile::tempdir;
92
//! use std::process::Command;
93
//!
94
//! // Create a directory inside of `env::temp_dir()`.
95
//! let temp_dir = tempdir()?;
96
//!
97
//! // Spawn the `touch` command inside the temporary directory and collect the exit status
98
//! // Note that `temp_dir` is **not** moved into `current_dir`, but passed as a reference
99
//! let exit_status = Command::new("touch").arg("tmp").current_dir(&temp_dir).status()?;
100
//! assert!(exit_status.success());
101
//!
102
//! # Ok::<(), std::io::Error>(())
103
//! ```
104
//!
105
//! This works because a reference to `temp_dir` is passed to `current_dir`, resulting in the
106
//! destructor of `temp_dir` being run after the `Command` has finished execution. Moving the
107
//! `TempDir` into the `current_dir` call would result in the `TempDir` being converted into
108
//! an internal representation, with the original value being dropped and the directory thus
109
//! being deleted, before the command can be executed.
110
//!
111
//! The `touch` command would fail with an `No such file or directory` error.
112
//!
113
//! ## Examples
114
//!
115
//! Create a temporary file and write some data into it:
116
//!
117
//! ```
118
//! use tempfile::tempfile;
119
//! use std::io::Write;
120
//!
121
//! // Create a file inside of `env::temp_dir()`.
122
//! let mut file = tempfile()?;
123
//!
124
//! writeln!(file, "Brian was here. Briefly.")?;
125
//! # Ok::<(), std::io::Error>(())
126
//! ```
127
//!
128
//! Create a named temporary file and open an independent file handle:
129
//!
130
//! ```
131
//! use tempfile::NamedTempFile;
132
//! use std::io::{Write, Read};
133
//!
134
//! let text = "Brian was here. Briefly.";
135
//!
136
//! // Create a file inside of `env::temp_dir()`.
137
//! let mut file1 = NamedTempFile::new()?;
138
//!
139
//! // Re-open it.
140
//! let mut file2 = file1.reopen()?;
141
//!
142
//! // Write some test data to the first handle.
143
//! file1.write_all(text.as_bytes())?;
144
//!
145
//! // Read the test data using the second handle.
146
//! let mut buf = String::new();
147
//! file2.read_to_string(&mut buf)?;
148
//! assert_eq!(buf, text);
149
//! # Ok::<(), std::io::Error>(())
150
//! ```
151
//!
152
//! Create a temporary directory and add a file to it:
153
//!
154
//! ```
155
//! use tempfile::tempdir;
156
//! use std::fs::File;
157
//! use std::io::Write;
158
//!
159
//! // Create a directory inside of `env::temp_dir()`.
160
//! let dir = tempdir()?;
161
//!
162
//! let file_path = dir.path().join("my-temporary-note.txt");
163
//! let mut file = File::create(file_path)?;
164
//! writeln!(file, "Brian was here. Briefly.")?;
165
//!
166
//! // By closing the `TempDir` explicitly, we can check that it has
167
//! // been deleted successfully. If we don't close it explicitly,
168
//! // the directory will still be deleted when `dir` goes out
169
//! // of scope, but we won't know whether deleting the directory
170
//! // succeeded.
171
//! drop(file);
172
//! dir.close()?;
173
//! # Ok::<(), std::io::Error>(())
174
//! ```
175
//!
176
//! [`tempfile()`]: fn.tempfile.html
177
//! [`tempdir()`]: fn.tempdir.html
178
//! [`TempDir`]: struct.TempDir.html
179
//! [`NamedTempFile`]: struct.NamedTempFile.html
180
//! [`lazy_static`]: https://github.com/rust-lang-nursery/lazy-static.rs/issues/62
181
182
#![doc(
183
    html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
184
    html_favicon_url = "https://www.rust-lang.org/favicon.ico",
185
    html_root_url = "https://docs.rs/tempfile/latest"
186
)]
187
#![cfg_attr(test, deny(warnings))]
188
#![deny(rust_2018_idioms)]
189
#![allow(clippy::redundant_field_names)]
190
191
#[cfg(doctest)]
192
doc_comment::doctest!("../README.md");
193
194
const NUM_RETRIES: u32 = 65536;
195
const NUM_RAND_CHARS: usize = 6;
196
197
use std::ffi::OsStr;
198
use std::fs::{OpenOptions, Permissions};
199
use std::io;
200
use std::path::Path;
201
202
mod dir;
203
mod error;
204
mod file;
205
mod spooled;
206
mod util;
207
208
pub mod env;
209
210
pub use crate::dir::{tempdir, tempdir_in, TempDir};
211
pub use crate::file::{
212
    tempfile, tempfile_in, NamedTempFile, PathPersistError, PersistError, TempPath,
213
};
214
pub use crate::spooled::{spooled_tempfile, spooled_tempfile_in, SpooledData, SpooledTempFile};
215
216
/// Create a new temporary file or directory with custom options.
217
#[derive(Debug, Clone, Eq, PartialEq)]
218
pub struct Builder<'a, 'b> {
219
    random_len: usize,
220
    prefix: &'a OsStr,
221
    suffix: &'b OsStr,
222
    append: bool,
223
    permissions: Option<Permissions>,
224
    disable_cleanup: bool,
225
}
226
227
impl Default for Builder<'_, '_> {
228
7.75k
    fn default() -> Self {
229
7.75k
        Builder {
230
7.75k
            random_len: crate::NUM_RAND_CHARS,
231
7.75k
            prefix: OsStr::new(".tmp"),
232
7.75k
            suffix: OsStr::new(""),
233
7.75k
            append: false,
234
7.75k
            permissions: None,
235
7.75k
            disable_cleanup: false,
236
7.75k
        }
237
7.75k
    }
238
}
239
240
impl<'a, 'b> Builder<'a, 'b> {
241
    /// Create a new `Builder`.
242
    ///
243
    /// # Examples
244
    ///
245
    /// Create a named temporary file and write some data into it:
246
    ///
247
    /// ```
248
    /// use std::ffi::OsStr;
249
    /// use tempfile::Builder;
250
    ///
251
    /// let named_tempfile = Builder::new()
252
    ///     .prefix("my-temporary-note")
253
    ///     .suffix(".txt")
254
    ///     .rand_bytes(5)
255
    ///     .tempfile()?;
256
    ///
257
    /// let name = named_tempfile
258
    ///     .path()
259
    ///     .file_name().and_then(OsStr::to_str);
260
    ///
261
    /// if let Some(name) = name {
262
    ///     assert!(name.starts_with("my-temporary-note"));
263
    ///     assert!(name.ends_with(".txt"));
264
    ///     assert_eq!(name.len(), "my-temporary-note.txt".len() + 5);
265
    /// }
266
    /// # Ok::<(), std::io::Error>(())
267
    /// ```
268
    ///
269
    /// Create a temporary directory and add a file to it:
270
    ///
271
    /// ```
272
    /// use std::io::Write;
273
    /// use std::fs::File;
274
    /// use std::ffi::OsStr;
275
    /// use tempfile::Builder;
276
    ///
277
    /// let dir = Builder::new()
278
    ///     .prefix("my-temporary-dir")
279
    ///     .rand_bytes(5)
280
    ///     .tempdir()?;
281
    ///
282
    /// let file_path = dir.path().join("my-temporary-note.txt");
283
    /// let mut file = File::create(file_path)?;
284
    /// writeln!(file, "Brian was here. Briefly.")?;
285
    ///
286
    /// // By closing the `TempDir` explicitly, we can check that it has
287
    /// // been deleted successfully. If we don't close it explicitly,
288
    /// // the directory will still be deleted when `dir` goes out
289
    /// // of scope, but we won't know whether deleting the directory
290
    /// // succeeded.
291
    /// drop(file);
292
    /// dir.close()?;
293
    /// # Ok::<(), std::io::Error>(())
294
    /// ```
295
    ///
296
    /// Create a temporary directory with a chosen prefix under a chosen folder:
297
    ///
298
    /// ```no_run
299
    /// use tempfile::Builder;
300
    ///
301
    /// let dir = Builder::new()
302
    ///     .prefix("my-temporary-dir")
303
    ///     .tempdir_in("folder-with-tempdirs")?;
304
    /// # Ok::<(), std::io::Error>(())
305
    /// ```
306
    #[must_use]
307
7.75k
    pub fn new() -> Self {
308
7.75k
        Self::default()
309
7.75k
    }
310
311
    /// Set a custom filename prefix.
312
    ///
313
    /// Path separators are legal but not advisable.
314
    /// Default: `.tmp`.
315
    ///
316
    /// # Examples
317
    ///
318
    /// ```
319
    /// use tempfile::Builder;
320
    ///
321
    /// let named_tempfile = Builder::new()
322
    ///     .prefix("my-temporary-note")
323
    ///     .tempfile()?;
324
    /// # Ok::<(), std::io::Error>(())
325
    /// ```
326
0
    pub fn prefix<S: AsRef<OsStr> + ?Sized>(&mut self, prefix: &'a S) -> &mut Self {
327
0
        self.prefix = prefix.as_ref();
328
0
        self
329
0
    }
330
331
    /// Set a custom filename suffix.
332
    ///
333
    /// Path separators are legal but not advisable.
334
    /// Default: empty.
335
    ///
336
    /// # Examples
337
    ///
338
    /// ```
339
    /// use tempfile::Builder;
340
    ///
341
    /// let named_tempfile = Builder::new()
342
    ///     .suffix(".txt")
343
    ///     .tempfile()?;
344
    /// # Ok::<(), std::io::Error>(())
345
    /// ```
346
0
    pub fn suffix<S: AsRef<OsStr> + ?Sized>(&mut self, suffix: &'b S) -> &mut Self {
347
0
        self.suffix = suffix.as_ref();
348
0
        self
349
0
    }
350
351
    /// Set the number of random bytes.
352
    ///
353
    /// Default: `6`.
354
    ///
355
    /// # Examples
356
    ///
357
    /// ```
358
    /// use tempfile::Builder;
359
    ///
360
    /// let named_tempfile = Builder::new()
361
    ///     .rand_bytes(5)
362
    ///     .tempfile()?;
363
    /// # Ok::<(), std::io::Error>(())
364
    /// ```
365
0
    pub fn rand_bytes(&mut self, rand: usize) -> &mut Self {
366
0
        self.random_len = rand;
367
0
        self
368
0
    }
369
370
    /// Configure the file to be opened in append-only mode.
371
    ///
372
    /// Default: `false`.
373
    ///
374
    /// # Examples
375
    ///
376
    /// ```
377
    /// use tempfile::Builder;
378
    ///
379
    /// let named_tempfile = Builder::new()
380
    ///     .append(true)
381
    ///     .tempfile()?;
382
    /// # Ok::<(), std::io::Error>(())
383
    /// ```
384
0
    pub fn append(&mut self, append: bool) -> &mut Self {
385
0
        self.append = append;
386
0
        self
387
0
    }
388
389
    /// Set the permissions for the new temporary file/directory.
390
    ///
391
    /// # Platform Notes
392
    ///
393
    /// ## Windows
394
    ///
395
    /// This setting is only fully-supported on unix-like platforms. On Windows, if this method is
396
    /// called with a [`Permissions`] object where `permissions.readonly` returns true, creating
397
    /// temporary files and directories will fail with an error.
398
    ///
399
    /// ## Unix
400
    ///
401
    /// On unix-like systems, the actual permission bits set on the tempfile or tempdir will be
402
    /// affected by the `umask` applied by the underlying syscall. The actual permission bits are
403
    /// calculated via `permissions & !umask`. In other words, depending on your umask, the
404
    /// permissions of the created file may be more restrictive (but never more permissive) than the
405
    /// ones you specified.
406
    ///
407
    /// Permissions default to `0o600` for tempfiles and `0o777` for tempdirs. Note, this doesn't
408
    /// include effects of the current `umask`. For example, combined with the standard umask
409
    /// `0o022`, the defaults yield `0o600` for tempfiles and `0o755` for tempdirs.
410
    ///
411
    /// ## WASI
412
    ///
413
    /// While custom permissions are allowed on WASI, they will be ignored as the platform has no
414
    /// concept of permissions or file modes (or multiple users for that matter).
415
    ///
416
    /// # Examples
417
    ///
418
    /// Create a named temporary file that is world-readable.
419
    ///
420
    /// ```
421
    /// # #[cfg(unix)]
422
    /// # {
423
    /// use tempfile::Builder;
424
    /// use std::os::unix::fs::PermissionsExt;
425
    ///
426
    /// let all_read_write = std::fs::Permissions::from_mode(0o666);
427
    /// let tempfile = Builder::new().permissions(all_read_write).tempfile()?;
428
    ///
429
    /// // Check that this worked and that the file is world-readable.
430
    /// //
431
    /// // NOTE: the file likely won't actually be created with 0o666 permissions because it's
432
    /// // restricted by the user's umask.
433
    /// //
434
    /// // NOTE: This test will fail if the user's umask is, e.g., 0o066.
435
    /// let actual_permissions = tempfile.path().metadata()?.permissions();
436
    /// assert_eq!(actual_permissions.mode() & 0o044, 0o044);
437
    /// # }
438
    /// # Ok::<(), std::io::Error>(())
439
    /// ```
440
    ///
441
    /// Create a named temporary directory that is restricted to the owner.
442
    ///
443
    /// ```
444
    /// # #[cfg(unix)]
445
    /// # {
446
    /// use tempfile::Builder;
447
    /// use std::os::unix::fs::PermissionsExt;
448
    ///
449
    /// let owner_rwx = std::fs::Permissions::from_mode(0o700);
450
    /// let tempdir = Builder::new().permissions(owner_rwx).tempdir()?;
451
    /// let actual_permissions = tempdir.path().metadata()?.permissions();
452
    /// assert_eq!(
453
    ///     actual_permissions.mode() & !0o170000,
454
    ///     0o700,
455
    ///     "we get the narrow permissions we asked for"
456
    /// );
457
    /// # }
458
    /// # Ok::<(), std::io::Error>(())
459
    /// ```
460
0
    pub fn permissions(&mut self, permissions: Permissions) -> &mut Self {
461
0
        self.permissions = Some(permissions);
462
0
        self
463
0
    }
464
465
    /// Disable cleanup of the file/folder to even when the [`NamedTempFile`]/[`TempDir`] goes out
466
    /// of scope. Prefer [`NamedTempFile::keep`] and [`TempDir::keep`] where possible;
467
    /// `disable_cleanup` is provided for testing & debugging.
468
    ///
469
    /// By default, the file/folder is automatically cleaned up in the destructor of
470
    /// [`NamedTempFile`]/[`TempDir`]. When `disable_cleanup` is set to `true`, this behavior is
471
    /// suppressed. If you wish to disable cleanup after creating a temporary file/directory, call
472
    /// [`NamedTempFile::disable_cleanup`] or [`TempDir::disable_cleanup`].
473
    ///
474
    /// # Warnings
475
    ///
476
    /// On some platforms (for now, only Windows), temporary files are marked with a special
477
    /// "temporary file" (`FILE_ATTRIBUTE_TEMPORARY`) attribute. Disabling cleanup _will not_ unset
478
    /// this attribute while calling [`NamedTempFile::keep`] will.
479
    ///
480
    /// # Examples
481
    ///
482
    /// ```
483
    /// use tempfile::Builder;
484
    ///
485
    /// let named_tempfile = Builder::new()
486
    ///     .disable_cleanup(true)
487
    ///     .tempfile()?;
488
    /// # Ok::<(), std::io::Error>(())
489
    /// ```
490
0
    pub fn disable_cleanup(&mut self, disable_cleanup: bool) -> &mut Self {
491
0
        self.disable_cleanup = disable_cleanup;
492
0
        self
493
0
    }
494
495
    /// Deprecated alias for [`Builder::disable_cleanup`].
496
    #[deprecated = "Use Builder::disable_cleanup"]
497
0
    pub fn keep(&mut self, keep: bool) -> &mut Self {
498
0
        self.disable_cleanup(keep)
499
0
    }
500
501
    /// Create the named temporary file.
502
    ///
503
    /// # Security
504
    ///
505
    /// See [the security][security] docs on `NamedTempFile`.
506
    ///
507
    /// # Resource leaking
508
    ///
509
    /// See [the resource leaking][resource-leaking] docs on `NamedTempFile`.
510
    ///
511
    /// # Errors
512
    ///
513
    /// If the file cannot be created, `Err` is returned.
514
    ///
515
    /// # Examples
516
    ///
517
    /// ```
518
    /// use tempfile::Builder;
519
    ///
520
    /// let tempfile = Builder::new().tempfile()?;
521
    /// # Ok::<(), std::io::Error>(())
522
    /// ```
523
    ///
524
    /// [security]: struct.NamedTempFile.html#security
525
    /// [resource-leaking]: struct.NamedTempFile.html#resource-leaking
526
2.76k
    pub fn tempfile(&self) -> io::Result<NamedTempFile> {
527
2.76k
        self.tempfile_in(env::temp_dir())
528
2.76k
    }
529
530
    /// Create the named temporary file in the specified directory.
531
    ///
532
    /// # Security
533
    ///
534
    /// See [the security][security] docs on `NamedTempFile`.
535
    ///
536
    /// # Resource leaking
537
    ///
538
    /// See [the resource leaking][resource-leaking] docs on `NamedTempFile`.
539
    ///
540
    /// # Errors
541
    ///
542
    /// If the file cannot be created, `Err` is returned.
543
    ///
544
    /// # Examples
545
    ///
546
    /// ```
547
    /// use tempfile::Builder;
548
    ///
549
    /// let tempfile = Builder::new().tempfile_in("./")?;
550
    /// # Ok::<(), std::io::Error>(())
551
    /// ```
552
    ///
553
    /// [security]: struct.NamedTempFile.html#security
554
    /// [resource-leaking]: struct.NamedTempFile.html#resource-leaking
555
2.76k
    pub fn tempfile_in<P: AsRef<Path>>(&self, dir: P) -> io::Result<NamedTempFile> {
556
2.76k
        util::create_helper(
557
2.76k
            dir.as_ref(),
558
2.76k
            self.prefix,
559
2.76k
            self.suffix,
560
2.76k
            self.random_len,
561
2.76k
            |path| {
562
2.76k
                file::create_named(
563
2.76k
                    path,
564
2.76k
                    OpenOptions::new().append(self.append),
565
2.76k
                    self.permissions.as_ref(),
566
2.76k
                    self.disable_cleanup,
567
                )
568
2.76k
            },
569
        )
570
2.76k
    }
571
572
    /// Attempts to make a temporary directory inside of [`env::temp_dir()`] whose
573
    /// name will have the prefix, `prefix`. The directory and
574
    /// everything inside it will be automatically deleted once the
575
    /// returned `TempDir` is destroyed.
576
    ///
577
    /// # Resource leaking
578
    ///
579
    /// See [the resource leaking][resource-leaking] docs on `TempDir`.
580
    ///
581
    /// # Errors
582
    ///
583
    /// If the directory can not be created, `Err` is returned.
584
    ///
585
    /// # Examples
586
    ///
587
    /// ```
588
    /// use tempfile::Builder;
589
    ///
590
    /// let tmp_dir = Builder::new().tempdir()?;
591
    /// # Ok::<(), std::io::Error>(())
592
    /// ```
593
    ///
594
    /// [resource-leaking]: struct.TempDir.html#resource-leaking
595
4.98k
    pub fn tempdir(&self) -> io::Result<TempDir> {
596
4.98k
        self.tempdir_in(env::temp_dir())
597
4.98k
    }
598
599
    /// Attempts to make a temporary directory inside of `dir`.
600
    /// The directory and everything inside it will be automatically
601
    /// deleted once the returned `TempDir` is destroyed.
602
    ///
603
    /// # Resource leaking
604
    ///
605
    /// See [the resource leaking][resource-leaking] docs on `TempDir`.
606
    ///
607
    /// # Errors
608
    ///
609
    /// If the directory can not be created, `Err` is returned.
610
    ///
611
    /// # Examples
612
    ///
613
    /// ```
614
    /// use tempfile::Builder;
615
    ///
616
    /// let tmp_dir = Builder::new().tempdir_in("./")?;
617
    /// # Ok::<(), std::io::Error>(())
618
    /// ```
619
    ///
620
    /// [resource-leaking]: struct.TempDir.html#resource-leaking
621
4.98k
    pub fn tempdir_in<P: AsRef<Path>>(&self, dir: P) -> io::Result<TempDir> {
622
4.98k
        util::create_helper(
623
4.98k
            dir.as_ref(),
624
4.98k
            self.prefix,
625
4.98k
            self.suffix,
626
4.98k
            self.random_len,
627
4.98k
            |path| dir::create(path, self.permissions.as_ref(), self.disable_cleanup),
628
        )
629
4.98k
    }
630
631
    /// Attempts to create a temporary file (or file-like object) using the
632
    /// provided closure. The closure is passed a temporary file path and
633
    /// returns an [`std::io::Result`]. The path provided to the closure will be
634
    /// inside of [`env::temp_dir()`]. Use [`Builder::make_in`] to provide
635
    /// a custom temporary directory. If the closure returns one of the
636
    /// following errors, then another randomized file path is tried:
637
    ///  - [`std::io::ErrorKind::AlreadyExists`]
638
    ///  - [`std::io::ErrorKind::AddrInUse`]
639
    ///
640
    /// This can be helpful for taking full control over the file creation, but
641
    /// leaving the temporary file path construction up to the library. This
642
    /// also enables creating a temporary UNIX domain socket, since it is not
643
    /// possible to bind to a socket that already exists.
644
    ///
645
    /// Note that [`Builder::append`] is ignored when using [`Builder::make`].
646
    ///
647
    /// # Security
648
    ///
649
    /// This has the same [security implications][security] as
650
    /// [`NamedTempFile`], but with additional caveats. Specifically, it is up
651
    /// to the closure to ensure that the file does not exist and that such a
652
    /// check is *atomic*. Otherwise, a [time-of-check to time-of-use
653
    /// bug][TOCTOU] could be introduced.
654
    ///
655
    /// For example, the following is **not** secure:
656
    ///
657
    /// ```
658
    /// use std::fs::File;
659
    /// use tempfile::Builder;
660
    ///
661
    /// // This is NOT secure!
662
    /// let tempfile = Builder::new().make(|path| {
663
    ///     if path.is_file() {
664
    ///         return Err(std::io::ErrorKind::AlreadyExists.into());
665
    ///     }
666
    ///
667
    ///     // Between the check above and the usage below, an attacker could
668
    ///     // have replaced `path` with another file, which would get truncated
669
    ///     // by `File::create`.
670
    ///
671
    ///     File::create(path)
672
    /// })?;
673
    /// # Ok::<(), std::io::Error>(())
674
    /// ```
675
    ///
676
    /// Note that simply using [`std::fs::File::create`] alone is not correct
677
    /// because it does not fail if the file already exists:
678
    ///
679
    /// ```
680
    /// use tempfile::Builder;
681
    /// use std::fs::File;
682
    ///
683
    /// // This could overwrite an existing file!
684
    /// let tempfile = Builder::new().make(|path| File::create(path))?;
685
    /// # Ok::<(), std::io::Error>(())
686
    /// ```
687
    /// For creating regular temporary files, use [`Builder::tempfile`] instead
688
    /// to avoid these problems. This function is meant to enable more exotic
689
    /// use-cases.
690
    ///
691
    /// # Resource leaking
692
    ///
693
    /// See [the resource leaking][resource-leaking] docs on `NamedTempFile`.
694
    ///
695
    /// # Errors
696
    ///
697
    /// If the closure returns any error besides
698
    /// [`std::io::ErrorKind::AlreadyExists`] or
699
    /// [`std::io::ErrorKind::AddrInUse`], then `Err` is returned.
700
    ///
701
    /// # Examples
702
    /// ```
703
    /// # #[cfg(unix)]
704
    /// # {
705
    /// use std::os::unix::net::UnixListener;
706
    /// use tempfile::Builder;
707
    ///
708
    /// let tempsock = Builder::new().make(|path| UnixListener::bind(path))?;
709
    /// # }
710
    /// # Ok::<(), std::io::Error>(())
711
    /// ```
712
    ///
713
    /// [TOCTOU]: https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use
714
    /// [security]: struct.NamedTempFile.html#security
715
    /// [resource-leaking]: struct.NamedTempFile.html#resource-leaking
716
0
    pub fn make<F, R>(&self, f: F) -> io::Result<NamedTempFile<R>>
717
0
    where
718
0
        F: FnMut(&Path) -> io::Result<R>,
719
    {
720
0
        self.make_in(env::temp_dir(), f)
721
0
    }
722
723
    /// This is the same as [`Builder::make`], except `dir` is used as the base
724
    /// directory for the temporary file path.
725
    ///
726
    /// See [`Builder::make`] for more details and security implications.
727
    ///
728
    /// # Examples
729
    /// ```
730
    /// # #[cfg(unix)]
731
    /// # {
732
    /// use tempfile::Builder;
733
    /// use std::os::unix::net::UnixListener;
734
    ///
735
    /// let tempsock = Builder::new().make_in("./", |path| UnixListener::bind(path))?;
736
    /// # }
737
    /// # Ok::<(), std::io::Error>(())
738
    /// ```
739
0
    pub fn make_in<F, R, P>(&self, dir: P, mut f: F) -> io::Result<NamedTempFile<R>>
740
0
    where
741
0
        F: FnMut(&Path) -> io::Result<R>,
742
0
        P: AsRef<Path>,
743
    {
744
0
        util::create_helper(
745
0
            dir.as_ref(),
746
0
            self.prefix,
747
0
            self.suffix,
748
0
            self.random_len,
749
0
            move |path| {
750
0
                Ok(NamedTempFile::from_parts(
751
0
                    f(&path)?,
752
0
                    TempPath::new(path, self.disable_cleanup),
753
                ))
754
0
            },
755
        )
756
0
    }
757
}