Coverage Report

Created: 2025-11-16 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/tempfile-3.23.0/src/dir/mod.rs
Line
Count
Source
1
// Copyright 2015 The Rust Project Developers.
2
//
3
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6
// option. This file may not be copied, modified, or distributed
7
// except according to those terms.
8
9
use std::ffi::OsStr;
10
use std::fs::remove_dir_all;
11
use std::mem;
12
use std::path::{self, Path, PathBuf};
13
use std::{fmt, io};
14
15
use crate::error::IoResultExt;
16
use crate::Builder;
17
18
#[cfg(doc)]
19
use crate::env;
20
21
/// Create a new temporary directory. Also see [`tempdir_in`].
22
///
23
/// The `tempdir` function creates a directory in the file system and returns a
24
/// [`TempDir`]. The directory will be automatically deleted when the `TempDir`'s
25
/// destructor is run.
26
///
27
/// # Resource Leaking
28
///
29
/// See [the resource leaking][resource-leaking] docs on `TempDir`.
30
///
31
/// # Security
32
///
33
/// Temporary directories are created with the default permissions unless otherwise
34
/// specified via [`Builder::permissions`]. Depending on your platform, this may make
35
/// them world-readable.
36
///
37
/// # Errors
38
///
39
/// If the directory can not be created, `Err` is returned.
40
///
41
/// # Examples
42
///
43
/// ```
44
/// use tempfile::tempdir;
45
/// use std::fs::File;
46
/// use std::io::Write;
47
///
48
/// // Create a directory inside of `env::temp_dir()`
49
/// let tmp_dir = tempdir()?;
50
///
51
/// let file_path = tmp_dir.path().join("my-temporary-note.txt");
52
/// let mut tmp_file = File::create(file_path)?;
53
/// writeln!(tmp_file, "Brian was here. Briefly.")?;
54
///
55
/// // `tmp_dir` goes out of scope, the directory as well as
56
/// // `tmp_file` will be deleted here.
57
/// drop(tmp_file);
58
/// tmp_dir.close()?;
59
/// # Ok::<(), std::io::Error>(())
60
/// ```
61
///
62
/// [`TempDir`]: struct.TempDir.html
63
/// [resource-leaking]: struct.TempDir.html#resource-leaking
64
4.88k
pub fn tempdir() -> io::Result<TempDir> {
65
4.88k
    TempDir::new()
66
4.88k
}
67
68
/// Create a new temporary directory in a specific directory. Also see [`tempdir`].
69
///
70
/// The `tempdir_in` function creates a directory in the specified directory
71
/// and returns a [`TempDir`].
72
/// The directory will be automatically deleted when the `TempDir`s
73
/// destructor is run.
74
///
75
/// # Resource Leaking
76
///
77
/// See [the resource leaking][resource-leaking] docs on `TempDir`.
78
///
79
/// # Errors
80
///
81
/// If the directory can not be created, `Err` is returned.
82
///
83
/// # Examples
84
///
85
/// ```
86
/// use tempfile::tempdir_in;
87
/// use std::fs::File;
88
/// use std::io::Write;
89
///
90
/// // Create a directory inside of the current directory.
91
/// let tmp_dir = tempdir_in(".")?;
92
///
93
/// let file_path = tmp_dir.path().join("my-temporary-note.txt");
94
/// let mut tmp_file = File::create(file_path)?;
95
/// writeln!(tmp_file, "Brian was here. Briefly.")?;
96
///
97
/// // `tmp_dir` goes out of scope, the directory as well as
98
/// // `tmp_file` will be deleted here.
99
/// drop(tmp_file);
100
/// tmp_dir.close()?;
101
/// # Ok::<(), std::io::Error>(())
102
/// ```
103
///
104
/// [`TempDir`]: struct.TempDir.html
105
/// [resource-leaking]: struct.TempDir.html#resource-leaking
106
0
pub fn tempdir_in<P: AsRef<Path>>(dir: P) -> io::Result<TempDir> {
107
0
    TempDir::new_in(dir)
108
0
}
109
110
/// A directory in the filesystem that is automatically deleted when
111
/// it goes out of scope.
112
///
113
/// The [`TempDir`] type creates a directory on the file system that
114
/// is deleted once it goes out of scope. At construction, the
115
/// `TempDir` creates a new directory with a randomly generated name.
116
///
117
/// The default constructor, [`TempDir::new()`], creates directories in
118
/// the location returned by [`env::temp_dir()`], but `TempDir`
119
/// can be configured to manage a temporary directory in any location
120
/// by constructing with a [`Builder`].
121
///
122
/// After creating a `TempDir`, work with the file system by doing
123
/// standard [`std::fs`] file system operations on its [`Path`],
124
/// which can be retrieved with [`TempDir::path()`]. Once the `TempDir`
125
/// value is dropped, the directory at the path will be deleted, along
126
/// with any files and directories it contains. It is your responsibility
127
/// to ensure that no further file system operations are attempted
128
/// inside the temporary directory once it has been deleted.
129
///
130
/// # Resource Leaking
131
///
132
/// Various platform-specific conditions may cause `TempDir` to fail
133
/// to delete the underlying directory. It's important to ensure that
134
/// handles (like [`File`] and [`ReadDir`]) to files inside the
135
/// directory are dropped before the `TempDir` goes out of scope. The
136
/// `TempDir` destructor will silently ignore any errors in deleting
137
/// the directory; to instead handle errors call [`TempDir::close()`].
138
///
139
/// Note that if the program exits before the `TempDir` destructor is
140
/// run, such as via [`std::process::exit()`], by segfaulting, or by
141
/// receiving a signal like `SIGINT`, then the temporary directory
142
/// will not be deleted.
143
///
144
/// # Examples
145
///
146
/// Create a temporary directory with a generated name:
147
///
148
/// ```
149
/// use std::fs::File;
150
/// use std::io::Write;
151
/// use tempfile::TempDir;
152
///
153
/// // Create a directory inside of `env::temp_dir()`
154
/// let tmp_dir = TempDir::new()?;
155
/// # Ok::<(), std::io::Error>(())
156
/// ```
157
///
158
/// Create a temporary directory with a prefix in its name:
159
///
160
/// ```
161
/// use std::fs::File;
162
/// use std::io::Write;
163
/// use tempfile::Builder;
164
///
165
/// // Create a directory inside of `env::temp_dir()`,
166
/// // whose name will begin with 'example'.
167
/// let tmp_dir = Builder::new().prefix("example").tempdir()?;
168
/// # Ok::<(), std::io::Error>(())
169
/// ```
170
///
171
/// [`File`]: http://doc.rust-lang.org/std/fs/struct.File.html
172
/// [`Path`]: http://doc.rust-lang.org/std/path/struct.Path.html
173
/// [`ReadDir`]: http://doc.rust-lang.org/std/fs/struct.ReadDir.html
174
/// [`Builder`]: struct.Builder.html
175
/// [`TempDir::close()`]: struct.TempDir.html#method.close
176
/// [`TempDir::new()`]: struct.TempDir.html#method.new
177
/// [`TempDir::path()`]: struct.TempDir.html#method.path
178
/// [`TempDir`]: struct.TempDir.html
179
/// [`std::fs`]: http://doc.rust-lang.org/std/fs/index.html
180
/// [`std::process::exit()`]: http://doc.rust-lang.org/std/process/fn.exit.html
181
pub struct TempDir {
182
    path: Box<Path>,
183
    disable_cleanup: bool,
184
}
185
186
impl TempDir {
187
    /// Attempts to make a temporary directory inside of `env::temp_dir()`.
188
    ///
189
    /// See [`Builder`] for more configuration.
190
    ///
191
    /// The directory and everything inside it will be automatically deleted
192
    /// once the returned `TempDir` is destroyed.
193
    ///
194
    /// # Errors
195
    ///
196
    /// If the directory can not be created, `Err` is returned.
197
    ///
198
    /// # Examples
199
    ///
200
    /// ```
201
    /// use std::fs::File;
202
    /// use std::io::Write;
203
    /// use tempfile::TempDir;
204
    ///
205
    /// // Create a directory inside of `env::temp_dir()`
206
    /// let tmp_dir = TempDir::new()?;
207
    ///
208
    /// let file_path = tmp_dir.path().join("my-temporary-note.txt");
209
    /// let mut tmp_file = File::create(file_path)?;
210
    /// writeln!(tmp_file, "Brian was here. Briefly.")?;
211
    ///
212
    /// // `tmp_dir` goes out of scope, the directory as well as
213
    /// // `tmp_file` will be deleted here.
214
    /// # Ok::<(), std::io::Error>(())
215
    /// ```
216
    ///
217
    /// [`Builder`]: struct.Builder.html
218
4.88k
    pub fn new() -> io::Result<TempDir> {
219
4.88k
        Builder::new().tempdir()
220
4.88k
    }
221
222
    /// Attempts to make a temporary directory inside of `dir`.
223
    /// The directory and everything inside it will be automatically
224
    /// deleted once the returned `TempDir` is destroyed.
225
    ///
226
    /// # Errors
227
    ///
228
    /// If the directory can not be created, `Err` is returned.
229
    ///
230
    /// # Examples
231
    ///
232
    /// ```
233
    /// use std::fs::{self, File};
234
    /// use std::io::Write;
235
    /// use tempfile::TempDir;
236
    ///
237
    /// // Create a directory inside of the current directory
238
    /// let tmp_dir = TempDir::new_in(".")?;
239
    /// let file_path = tmp_dir.path().join("my-temporary-note.txt");
240
    /// let mut tmp_file = File::create(file_path)?;
241
    /// writeln!(tmp_file, "Brian was here. Briefly.")?;
242
    /// # Ok::<(), std::io::Error>(())
243
    /// ```
244
0
    pub fn new_in<P: AsRef<Path>>(dir: P) -> io::Result<TempDir> {
245
0
        Builder::new().tempdir_in(dir)
246
0
    }
247
248
    /// Attempts to make a temporary directory with the specified prefix inside of
249
    /// `env::temp_dir()`. The directory and everything inside it will be automatically
250
    /// deleted once the returned `TempDir` is destroyed.
251
    ///
252
    /// # Errors
253
    ///
254
    /// If the directory can not be created, `Err` is returned.
255
    ///
256
    /// # Examples
257
    ///
258
    /// ```
259
    /// use std::fs::{self, File};
260
    /// use std::io::Write;
261
    /// use tempfile::TempDir;
262
    ///
263
    /// // Create a directory inside of the current directory
264
    /// let tmp_dir = TempDir::with_prefix("foo-")?;
265
    /// let tmp_name = tmp_dir.path().file_name().unwrap().to_str().unwrap();
266
    /// assert!(tmp_name.starts_with("foo-"));
267
    /// # Ok::<(), std::io::Error>(())
268
    /// ```
269
0
    pub fn with_prefix<S: AsRef<OsStr>>(prefix: S) -> io::Result<TempDir> {
270
0
        Builder::new().prefix(&prefix).tempdir()
271
0
    }
272
273
    /// Attempts to make a temporary directory with the specified suffix inside of
274
    /// `env::temp_dir()`. The directory and everything inside it will be automatically
275
    /// deleted once the returned `TempDir` is destroyed.
276
    ///
277
    /// # Errors
278
    ///
279
    /// If the directory can not be created, `Err` is returned.
280
    ///
281
    /// # Examples
282
    ///
283
    /// ```
284
    /// use std::fs::{self, File};
285
    /// use std::io::Write;
286
    /// use tempfile::TempDir;
287
    ///
288
    /// // Create a directory inside of the current directory
289
    /// let tmp_dir = TempDir::with_suffix("-foo")?;
290
    /// let tmp_name = tmp_dir.path().file_name().unwrap().to_str().unwrap();
291
    /// assert!(tmp_name.ends_with("-foo"));
292
    /// # Ok::<(), std::io::Error>(())
293
    /// ```
294
0
    pub fn with_suffix<S: AsRef<OsStr>>(suffix: S) -> io::Result<TempDir> {
295
0
        Builder::new().suffix(&suffix).tempdir()
296
0
    }
297
    /// Attempts to make a temporary directory with the specified prefix inside
298
    /// the specified directory. The directory and everything inside it will be
299
    /// automatically deleted once the returned `TempDir` is destroyed.
300
    ///
301
    /// # Errors
302
    ///
303
    /// If the directory can not be created, `Err` is returned.
304
    ///
305
    /// # Examples
306
    ///
307
    /// ```
308
    /// use std::fs::{self, File};
309
    /// use std::io::Write;
310
    /// use tempfile::TempDir;
311
    ///
312
    /// // Create a directory inside of the current directory
313
    /// let tmp_dir = TempDir::with_suffix_in("-foo", ".")?;
314
    /// let tmp_name = tmp_dir.path().file_name().unwrap().to_str().unwrap();
315
    /// assert!(tmp_name.ends_with("-foo"));
316
    /// # Ok::<(), std::io::Error>(())
317
    /// ```
318
0
    pub fn with_suffix_in<S: AsRef<OsStr>, P: AsRef<Path>>(
319
0
        suffix: S,
320
0
        dir: P,
321
0
    ) -> io::Result<TempDir> {
322
0
        Builder::new().suffix(&suffix).tempdir_in(dir)
323
0
    }
324
325
    /// Attempts to make a temporary directory with the specified prefix inside
326
    /// the specified directory. The directory and everything inside it will be
327
    /// automatically deleted once the returned `TempDir` is destroyed.
328
    ///
329
    /// # Errors
330
    ///
331
    /// If the directory can not be created, `Err` is returned.
332
    ///
333
    /// # Examples
334
    ///
335
    /// ```
336
    /// use std::fs::{self, File};
337
    /// use std::io::Write;
338
    /// use tempfile::TempDir;
339
    ///
340
    /// // Create a directory inside of the current directory
341
    /// let tmp_dir = TempDir::with_prefix_in("foo-", ".")?;
342
    /// let tmp_name = tmp_dir.path().file_name().unwrap().to_str().unwrap();
343
    /// assert!(tmp_name.starts_with("foo-"));
344
    /// # Ok::<(), std::io::Error>(())
345
    /// ```
346
0
    pub fn with_prefix_in<S: AsRef<OsStr>, P: AsRef<Path>>(
347
0
        prefix: S,
348
0
        dir: P,
349
0
    ) -> io::Result<TempDir> {
350
0
        Builder::new().prefix(&prefix).tempdir_in(dir)
351
0
    }
352
353
    /// Accesses the [`Path`] to the temporary directory.
354
    ///
355
    /// [`Path`]: http://doc.rust-lang.org/std/path/struct.Path.html
356
    ///
357
    /// # Examples
358
    ///
359
    /// ```
360
    /// use tempfile::TempDir;
361
    ///
362
    /// let tmp_path;
363
    ///
364
    /// {
365
    ///    let tmp_dir = TempDir::new()?;
366
    ///    tmp_path = tmp_dir.path().to_owned();
367
    ///
368
    ///    // Check that the temp directory actually exists.
369
    ///    assert!(tmp_path.exists());
370
    ///
371
    ///    // End of `tmp_dir` scope, directory will be deleted
372
    /// }
373
    ///
374
    /// // Temp directory should be deleted by now
375
    /// assert_eq!(tmp_path.exists(), false);
376
    /// # Ok::<(), std::io::Error>(())
377
    /// ```
378
    #[must_use]
379
39.9k
    pub fn path(&self) -> &path::Path {
380
39.9k
        self.path.as_ref()
381
39.9k
    }
382
383
    /// Deprecated alias for [`TempDir::keep`].
384
    #[must_use]
385
    #[deprecated = "use TempDir::keep()"]
386
0
    pub fn into_path(self) -> PathBuf {
387
0
        self.keep()
388
0
    }
389
390
    /// Persist the temporary directory to disk, returning the [`PathBuf`] where it is located.
391
    ///
392
    /// This consumes the [`TempDir`] without deleting directory on the filesystem, meaning that
393
    /// the directory will no longer be automatically deleted.
394
    ///
395
    /// If you want to disable automatic cleanup of the temporary directory in-place, keeping the
396
    /// `TempDir` as-is, use [`TempDir::disable_cleanup`] instead.
397
    ///
398
    /// [`TempDir`]: struct.TempDir.html
399
    /// [`PathBuf`]: http://doc.rust-lang.org/std/path/struct.PathBuf.html
400
    ///
401
    /// # Examples
402
    ///
403
    /// ```
404
    /// use std::fs;
405
    /// use tempfile::TempDir;
406
    ///
407
    /// let tmp_dir = TempDir::new()?;
408
    ///
409
    /// // Persist the temporary directory to disk,
410
    /// // getting the path where it is.
411
    /// let tmp_path = tmp_dir.keep();
412
    ///
413
    /// // Delete the temporary directory ourselves.
414
    /// fs::remove_dir_all(tmp_path)?;
415
    /// # Ok::<(), std::io::Error>(())
416
    /// ```
417
    #[must_use]
418
0
    pub fn keep(mut self) -> PathBuf {
419
0
        self.disable_cleanup(true);
420
0
        mem::replace(&mut self.path, PathBuf::new().into_boxed_path()).into()
421
0
    }
422
423
    /// Disable cleanup of the temporary directory. If `disable_cleanup` is `true`, the temporary
424
    /// directory will not be deleted when this `TempDir` is dropped. This method is equivalent to
425
    /// calling [`Builder::disable_cleanup`] when creating the `TempDir`.
426
    ///
427
    /// **NOTE:** this method is primarily useful for testing/debugging. If you want to simply turn
428
    /// a temporary directory into a non-temporary directory, prefer [`TempDir::keep`].
429
0
    pub fn disable_cleanup(&mut self, disable_cleanup: bool) {
430
0
        self.disable_cleanup = disable_cleanup
431
0
    }
432
433
    /// Closes and removes the temporary directory, returning a `Result`.
434
    ///
435
    /// Although `TempDir` removes the directory on drop, in the destructor
436
    /// any errors are ignored. To detect errors cleaning up the temporary
437
    /// directory, call `close` instead.
438
    ///
439
    /// # Errors
440
    ///
441
    /// This function may return a variety of [`std::io::Error`]s that result from deleting
442
    /// the files and directories contained with the temporary directory,
443
    /// as well as from deleting the temporary directory itself. These errors
444
    /// may be platform specific.
445
    ///
446
    /// [`std::io::Error`]: http://doc.rust-lang.org/std/io/struct.Error.html
447
    ///
448
    /// # Examples
449
    ///
450
    /// ```
451
    /// use std::fs::File;
452
    /// use std::io::Write;
453
    /// use tempfile::TempDir;
454
    ///
455
    /// // Create a directory inside of `env::temp_dir()`.
456
    /// let tmp_dir = TempDir::new()?;
457
    /// let file_path = tmp_dir.path().join("my-temporary-note.txt");
458
    /// let mut tmp_file = File::create(file_path)?;
459
    /// writeln!(tmp_file, "Brian was here. Briefly.")?;
460
    ///
461
    /// // By closing the `TempDir` explicitly we can check that it has
462
    /// // been deleted successfully. If we don't close it explicitly,
463
    /// // the directory will still be deleted when `tmp_dir` goes out
464
    /// // of scope, but we won't know whether deleting the directory
465
    /// // succeeded.
466
    /// drop(tmp_file);
467
    /// tmp_dir.close()?;
468
    /// # Ok::<(), std::io::Error>(())
469
    /// ```
470
0
    pub fn close(mut self) -> io::Result<()> {
471
0
        let result = remove_dir_all(self.path()).with_err_path(|| self.path());
472
473
        // Set self.path to empty Box to release the memory, since an empty
474
        // Box does not allocate any heap memory.
475
0
        self.path = PathBuf::new().into_boxed_path();
476
477
        // Prevent the Drop impl from being called.
478
0
        mem::forget(self);
479
480
0
        result
481
0
    }
482
}
483
484
impl AsRef<Path> for TempDir {
485
0
    fn as_ref(&self) -> &Path {
486
0
        self.path()
487
0
    }
488
}
489
490
impl fmt::Debug for TempDir {
491
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
492
0
        f.debug_struct("TempDir")
493
0
            .field("path", &self.path())
494
0
            .finish()
495
0
    }
496
}
497
498
impl Drop for TempDir {
499
4.88k
    fn drop(&mut self) {
500
4.88k
        if !self.disable_cleanup {
501
4.88k
            let _ = remove_dir_all(self.path());
502
4.88k
        }
503
4.88k
    }
504
}
505
506
4.88k
pub(crate) fn create(
507
4.88k
    path: PathBuf,
508
4.88k
    permissions: Option<&std::fs::Permissions>,
509
4.88k
    disable_cleanup: bool,
510
4.88k
) -> io::Result<TempDir> {
511
4.88k
    imp::create(path, permissions, disable_cleanup)
512
4.88k
}
513
514
mod imp;