Coverage Report

Created: 2026-03-31 06:55

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