Coverage Report

Created: 2025-07-12 06:48

/rust/registry/src/index.crates.io-6f17d22bba15001f/tempfile-3.20.0/src/file/mod.rs
Line
Count
Source (jump to first uncovered line)
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(unix)]
9
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
10
#[cfg(target_os = "wasi")]
11
use std::os::wasi::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
329
    /// file exists at the given path.
330
    ///
331
    /// This is mostly useful for interacting with libraries and external
332
    /// components that provide files to be consumed or expect a path with no
333
    /// existing file to be given.
334
0
    pub fn from_path(path: impl Into<PathBuf>) -> Self {
335
0
        Self {
336
0
            path: path.into().into_boxed_path(),
337
0
            disable_cleanup: false,
338
0
        }
339
0
    }
340
341
0
    pub(crate) fn new(path: PathBuf, disable_cleanup: bool) -> Self {
342
0
        Self {
343
0
            path: path.into_boxed_path(),
344
0
            disable_cleanup,
345
0
        }
346
0
    }
347
}
348
349
impl fmt::Debug for TempPath {
350
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
351
0
        self.path.fmt(f)
352
0
    }
353
}
354
355
impl Drop for TempPath {
356
2.07k
    fn drop(&mut self) {
357
2.07k
        if !self.disable_cleanup {
358
2.07k
            let _ = fs::remove_file(&self.path);
359
2.07k
        }
360
2.07k
    }
361
}
362
363
impl Deref for TempPath {
364
    type Target = Path;
365
366
0
    fn deref(&self) -> &Path {
367
0
        &self.path
368
0
    }
369
}
370
371
impl AsRef<Path> for TempPath {
372
0
    fn as_ref(&self) -> &Path {
373
0
        &self.path
374
0
    }
375
}
376
377
impl AsRef<OsStr> for TempPath {
378
0
    fn as_ref(&self) -> &OsStr {
379
0
        self.path.as_os_str()
380
0
    }
381
}
382
383
/// A named temporary file.
384
///
385
/// The default constructor, [`NamedTempFile::new()`], creates files in
386
/// the location returned by [`env::temp_dir()`], but `NamedTempFile`
387
/// can be configured to manage a temporary file in any location
388
/// by constructing with [`NamedTempFile::new_in()`].
389
///
390
/// # Security
391
///
392
/// Most operating systems employ temporary file cleaners to delete old
393
/// temporary files. Unfortunately these temporary file cleaners don't always
394
/// reliably _detect_ whether the temporary file is still being used.
395
///
396
/// Specifically, the following sequence of events can happen:
397
///
398
/// 1. A user creates a temporary file with `NamedTempFile::new()`.
399
/// 2. Time passes.
400
/// 3. The temporary file cleaner deletes (unlinks) the temporary file from the
401
///    filesystem.
402
/// 4. Some other program creates a new file to replace this deleted temporary
403
///    file.
404
/// 5. The user tries to re-open the temporary file (in the same program or in a
405
///    different program) by path. Unfortunately, they'll end up opening the
406
///    file created by the other program, not the original file.
407
///
408
/// ## Operating System Specific Concerns
409
///
410
/// The behavior of temporary files and temporary file cleaners differ by
411
/// operating system.
412
///
413
/// ### Windows
414
///
415
/// On Windows, temporary files are, by default, created in per-user temporary
416
/// file directories so only an application running as the same user would be
417
/// able to interfere (which they could do anyways). However, an application
418
/// running as the same user can still _accidentally_ re-create deleted
419
/// temporary files if the number of random bytes in the temporary file name is
420
/// too small.
421
///
422
/// ### MacOS
423
///
424
/// Like on Windows, temporary files are created in per-user temporary file
425
/// directories by default so calling `NamedTempFile::new()` should be
426
/// relatively safe.
427
///
428
/// ### Linux
429
///
430
/// Unfortunately, most _Linux_ distributions don't create per-user temporary
431
/// file directories. Worse, systemd's tmpfiles daemon (a common temporary file
432
/// cleaner) will happily remove open temporary files if they haven't been
433
/// modified within the last 10 days.
434
///
435
/// # Resource Leaking
436
///
437
/// If the program exits before the `NamedTempFile` destructor is
438
/// run, the temporary file will not be deleted. This can happen
439
/// if the process exits using [`std::process::exit()`], a segfault occurs,
440
/// receiving an interrupt signal like `SIGINT` that is not handled, or by using
441
/// a statically declared `NamedTempFile` instance (like with [`lazy_static`]).
442
///
443
/// Use the [`tempfile()`] function unless you need a named file path.
444
///
445
/// [`tempfile()`]: fn.tempfile.html
446
/// [`NamedTempFile::new()`]: #method.new
447
/// [`NamedTempFile::new_in()`]: #method.new_in
448
/// [`std::process::exit()`]: http://doc.rust-lang.org/std/process/fn.exit.html
449
/// [`lazy_static`]: https://github.com/rust-lang-nursery/lazy-static.rs/issues/62
450
pub struct NamedTempFile<F = File> {
451
    path: TempPath,
452
    file: F,
453
}
454
455
impl<F> fmt::Debug for NamedTempFile<F> {
456
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
457
0
        write!(f, "NamedTempFile({:?})", self.path)
458
0
    }
459
}
460
461
impl<F> AsRef<Path> for NamedTempFile<F> {
462
    #[inline]
463
0
    fn as_ref(&self) -> &Path {
464
0
        self.path()
465
0
    }
466
}
467
468
/// Error returned when persisting a temporary file fails.
469
pub struct PersistError<F = File> {
470
    /// The underlying IO error.
471
    pub error: io::Error,
472
    /// The temporary file that couldn't be persisted.
473
    pub file: NamedTempFile<F>,
474
}
475
476
impl<F> fmt::Debug for PersistError<F> {
477
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
478
0
        write!(f, "PersistError({:?})", self.error)
479
0
    }
480
}
481
482
impl<F> From<PersistError<F>> for io::Error {
483
    #[inline]
484
0
    fn from(error: PersistError<F>) -> io::Error {
485
0
        error.error
486
0
    }
487
}
488
489
impl<F> From<PersistError<F>> for NamedTempFile<F> {
490
    #[inline]
491
0
    fn from(error: PersistError<F>) -> NamedTempFile<F> {
492
0
        error.file
493
0
    }
494
}
495
496
impl<F> fmt::Display for PersistError<F> {
497
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
498
0
        write!(f, "failed to persist temporary file: {}", self.error)
499
0
    }
500
}
501
502
impl<F> error::Error for PersistError<F> {
503
0
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
504
0
        Some(&self.error)
505
0
    }
506
}
507
508
impl NamedTempFile<File> {
509
    /// Create a new named temporary file.
510
    ///
511
    /// See [`Builder`] for more configuration.
512
    ///
513
    /// # Security
514
    ///
515
    /// This will create a temporary file in the default temporary file
516
    /// directory (platform dependent). This has security implications on many
517
    /// platforms so please read the security section of this type's
518
    /// documentation.
519
    ///
520
    /// Reasons to use this method:
521
    ///
522
    ///   1. The file has a short lifetime and your temporary file cleaner is
523
    ///      sane (doesn't delete recently accessed files).
524
    ///
525
    ///   2. You trust every user on your system (i.e. you are the only user).
526
    ///
527
    ///   3. You have disabled your system's temporary file cleaner or verified
528
    ///      that your system doesn't have a temporary file cleaner.
529
    ///
530
    /// Reasons not to use this method:
531
    ///
532
    ///   1. You'll fix it later. No you won't.
533
    ///
534
    ///   2. You don't care about the security of the temporary file. If none of
535
    ///      the "reasons to use this method" apply, referring to a temporary
536
    ///      file by name may allow an attacker to create/overwrite your
537
    ///      non-temporary files. There are exceptions but if you don't already
538
    ///      know them, don't use this method.
539
    ///
540
    /// # Errors
541
    ///
542
    /// If the file can not be created, `Err` is returned.
543
    ///
544
    /// # Examples
545
    ///
546
    /// Create a named temporary file and write some data to it:
547
    ///
548
    /// ```no_run
549
    /// use std::io::Write;
550
    /// use tempfile::NamedTempFile;
551
    ///
552
    /// let mut file = NamedTempFile::new()?;
553
    ///
554
    /// writeln!(file, "Brian was here. Briefly.")?;
555
    /// # Ok::<(), std::io::Error>(())
556
    /// ```
557
    ///
558
    /// [`Builder`]: struct.Builder.html
559
2.07k
    pub fn new() -> io::Result<NamedTempFile> {
560
2.07k
        Builder::new().tempfile()
561
2.07k
    }
562
563
    /// Create a new named temporary file in the specified directory.
564
    ///
565
    /// This is equivalent to:
566
    ///
567
    /// ```ignore
568
    /// Builder::new().tempfile_in(dir)
569
    /// ```
570
    ///
571
    /// See [`NamedTempFile::new()`] for details.
572
    ///
573
    /// [`NamedTempFile::new()`]: #method.new
574
0
    pub fn new_in<P: AsRef<Path>>(dir: P) -> io::Result<NamedTempFile> {
575
0
        Builder::new().tempfile_in(dir)
576
0
    }
577
578
    /// Create a new named temporary file with the specified filename suffix.
579
    ///
580
    /// See [`NamedTempFile::new()`] for details.
581
    ///
582
    /// [`NamedTempFile::new()`]: #method.new
583
0
    pub fn with_suffix<S: AsRef<OsStr>>(suffix: S) -> io::Result<NamedTempFile> {
584
0
        Builder::new().suffix(&suffix).tempfile()
585
0
    }
586
    /// Create a new named temporary file with the specified filename suffix,
587
    /// in the specified directory.
588
    ///
589
    /// This is equivalent to:
590
    ///
591
    /// ```ignore
592
    /// Builder::new().suffix(&suffix).tempfile_in(directory)
593
    /// ```
594
    ///
595
    /// See [`NamedTempFile::new()`] for details.
596
    ///
597
    /// [`NamedTempFile::new()`]: #method.new
598
0
    pub fn with_suffix_in<S: AsRef<OsStr>, P: AsRef<Path>>(
599
0
        suffix: S,
600
0
        dir: P,
601
0
    ) -> io::Result<NamedTempFile> {
602
0
        Builder::new().suffix(&suffix).tempfile_in(dir)
603
0
    }
604
605
    /// Create a new named temporary file with the specified filename prefix.
606
    ///
607
    /// See [`NamedTempFile::new()`] for details.
608
    ///
609
    /// [`NamedTempFile::new()`]: #method.new
610
0
    pub fn with_prefix<S: AsRef<OsStr>>(prefix: S) -> io::Result<NamedTempFile> {
611
0
        Builder::new().prefix(&prefix).tempfile()
612
0
    }
613
    /// Create a new named temporary file with the specified filename prefix,
614
    /// in the specified directory.
615
    ///
616
    /// This is equivalent to:
617
    ///
618
    /// ```ignore
619
    /// Builder::new().prefix(&prefix).tempfile_in(directory)
620
    /// ```
621
    ///
622
    /// See [`NamedTempFile::new()`] for details.
623
    ///
624
    /// [`NamedTempFile::new()`]: #method.new
625
0
    pub fn with_prefix_in<S: AsRef<OsStr>, P: AsRef<Path>>(
626
0
        prefix: S,
627
0
        dir: P,
628
0
    ) -> io::Result<NamedTempFile> {
629
0
        Builder::new().prefix(&prefix).tempfile_in(dir)
630
0
    }
631
}
632
633
impl<F> NamedTempFile<F> {
634
    /// Get the temporary file's path.
635
    ///
636
    /// # Security
637
    ///
638
    /// Referring to a temporary file's path may not be secure in all cases.
639
    /// Please read the security section on the top level documentation of this
640
    /// type for details.
641
    ///
642
    /// # Examples
643
    ///
644
    /// ```no_run
645
    /// use tempfile::NamedTempFile;
646
    ///
647
    /// let file = NamedTempFile::new()?;
648
    ///
649
    /// println!("{:?}", file.path());
650
    /// # Ok::<(), std::io::Error>(())
651
    /// ```
652
    #[inline]
653
0
    pub fn path(&self) -> &Path {
654
0
        &self.path
655
0
    }
656
657
    /// Close and remove the temporary file.
658
    ///
659
    /// Use this if you want to detect errors in deleting the file.
660
    ///
661
    /// # Errors
662
    ///
663
    /// If the file cannot be deleted, `Err` is returned.
664
    ///
665
    /// # Examples
666
    ///
667
    /// ```no_run
668
    /// use tempfile::NamedTempFile;
669
    ///
670
    /// let file = NamedTempFile::new()?;
671
    ///
672
    /// // By closing the `NamedTempFile` explicitly, we can check that it has
673
    /// // been deleted successfully. If we don't close it explicitly,
674
    /// // the file will still be deleted when `file` goes out
675
    /// // of scope, but we won't know whether deleting the file
676
    /// // succeeded.
677
    /// file.close()?;
678
    /// # Ok::<(), std::io::Error>(())
679
    /// ```
680
0
    pub fn close(self) -> io::Result<()> {
681
0
        let NamedTempFile { path, .. } = self;
682
0
        path.close()
683
0
    }
684
685
    /// Persist the temporary file at the target path.
686
    ///
687
    /// If a file exists at the target path, persist will atomically replace it.
688
    /// If this method fails, it will return `self` in the resulting
689
    /// [`PersistError`].
690
    ///
691
    /// **Note:** Temporary files cannot be persisted across filesystems. Also
692
    /// neither the file contents nor the containing directory are
693
    /// synchronized, so the update may not yet have reached the disk when
694
    /// `persist` returns.
695
    ///
696
    /// # Security
697
    ///
698
    /// This method persists the temporary file using its path and may not be
699
    /// secure in all cases. Please read the security section on the top
700
    /// level documentation of this type for details.
701
    ///
702
    /// # Errors
703
    ///
704
    /// If the file cannot be moved to the new location, `Err` is returned.
705
    ///
706
    /// # Examples
707
    ///
708
    /// ```no_run
709
    /// use std::io::Write;
710
    /// use tempfile::NamedTempFile;
711
    ///
712
    /// let file = NamedTempFile::new()?;
713
    ///
714
    /// let mut persisted_file = file.persist("./saved_file.txt")?;
715
    /// writeln!(persisted_file, "Brian was here. Briefly.")?;
716
    /// # Ok::<(), std::io::Error>(())
717
    /// ```
718
    ///
719
    /// [`PersistError`]: struct.PersistError.html
720
0
    pub fn persist<P: AsRef<Path>>(self, new_path: P) -> Result<F, PersistError<F>> {
721
0
        let NamedTempFile { path, file } = self;
722
0
        match path.persist(new_path) {
723
0
            Ok(_) => Ok(file),
724
0
            Err(err) => {
725
0
                let PathPersistError { error, path } = err;
726
0
                Err(PersistError {
727
0
                    file: NamedTempFile { path, file },
728
0
                    error,
729
0
                })
730
            }
731
        }
732
0
    }
733
734
    /// Persist the temporary file at the target path if and only if no file exists there.
735
    ///
736
    /// If a file exists at the target path, fail. If this method fails, it will
737
    /// return `self` in the resulting PersistError.
738
    ///
739
    /// **Note:** Temporary files cannot be persisted across filesystems.
740
    ///
741
    /// **Atomicity:** This method is not guaranteed to be atomic on all platforms, although it will
742
    /// generally be atomic on Windows and modern Linux filesystems. While it will never overwrite a
743
    /// file at the target path, it may leave the original link to the temporary file behind leaving
744
    /// you with two [hard links][hardlink] in your filesystem pointing at the same underlying file.
745
    /// This can happen if either (a) we lack permission to "unlink" the original filename; (b) this
746
    /// program crashes while persisting the temporary file; or (c) the filesystem is removed,
747
    /// unmounted, etc. while we're performing this operation.
748
    ///
749
    /// # Security
750
    ///
751
    /// This method persists the temporary file using its path and may not be
752
    /// secure in all cases. Please read the security section on the top
753
    /// level documentation of this type for details.
754
    ///
755
    /// # Errors
756
    ///
757
    /// If the file cannot be moved to the new location or a file already exists there,
758
    /// `Err` is returned.
759
    ///
760
    /// # Examples
761
    ///
762
    /// ```no_run
763
    /// use std::io::Write;
764
    /// use tempfile::NamedTempFile;
765
    ///
766
    /// let file = NamedTempFile::new()?;
767
    ///
768
    /// let mut persisted_file = file.persist_noclobber("./saved_file.txt")?;
769
    /// writeln!(persisted_file, "Brian was here. Briefly.")?;
770
    /// # Ok::<(), std::io::Error>(())
771
    /// ```
772
    ///
773
    /// [hardlink]: https://en.wikipedia.org/wiki/Hard_link
774
0
    pub fn persist_noclobber<P: AsRef<Path>>(self, new_path: P) -> Result<F, PersistError<F>> {
775
0
        let NamedTempFile { path, file } = self;
776
0
        match path.persist_noclobber(new_path) {
777
0
            Ok(_) => Ok(file),
778
0
            Err(err) => {
779
0
                let PathPersistError { error, path } = err;
780
0
                Err(PersistError {
781
0
                    file: NamedTempFile { path, file },
782
0
                    error,
783
0
                })
784
            }
785
        }
786
0
    }
787
788
    /// Keep the temporary file from being deleted. This function will turn the
789
    /// temporary file into a non-temporary file without moving it.
790
    ///
791
    /// # Errors
792
    ///
793
    /// On some platforms (e.g., Windows), we need to mark the file as
794
    /// non-temporary. This operation could fail.
795
    ///
796
    /// # Examples
797
    ///
798
    /// ```no_run
799
    /// use std::io::Write;
800
    /// use tempfile::NamedTempFile;
801
    ///
802
    /// let mut file = NamedTempFile::new()?;
803
    /// writeln!(file, "Brian was here. Briefly.")?;
804
    ///
805
    /// let (file, path) = file.keep()?;
806
    /// # Ok::<(), std::io::Error>(())
807
    /// ```
808
    ///
809
    /// [`PathPersistError`]: struct.PathPersistError.html
810
0
    pub fn keep(self) -> Result<(F, PathBuf), PersistError<F>> {
811
0
        let (file, path) = (self.file, self.path);
812
0
        match path.keep() {
813
0
            Ok(path) => Ok((file, path)),
814
0
            Err(PathPersistError { error, path }) => Err(PersistError {
815
0
                file: NamedTempFile { path, file },
816
0
                error,
817
0
            }),
818
        }
819
0
    }
820
821
    /// Disable cleanup of the temporary file. If `disable_cleanup` is `true`, the temporary file
822
    /// will not be deleted when this `TempPath` is dropped. This method is equivalent to calling
823
    /// [`Builder::disable_cleanup`] when creating the original `NamedTempFile`, which see for
824
    /// relevant warnings.
825
    ///
826
    /// **NOTE:** this method is primarily useful for testing/debugging. If you want to simply turn
827
    /// a temporary file into a non-temporary file, prefer [`NamedTempFile::keep`].
828
0
    pub fn disable_cleanup(&mut self, disable_cleanup: bool) {
829
0
        self.path.disable_cleanup(disable_cleanup)
830
0
    }
831
832
    /// Get a reference to the underlying file.
833
0
    pub fn as_file(&self) -> &F {
834
0
        &self.file
835
0
    }
836
837
    /// Get a mutable reference to the underlying file.
838
4.14k
    pub fn as_file_mut(&mut self) -> &mut F {
839
4.14k
        &mut self.file
840
4.14k
    }
Unexecuted instantiation: <tempfile::file::NamedTempFile<_>>::as_file_mut
<tempfile::file::NamedTempFile>::as_file_mut
Line
Count
Source
838
4.14k
    pub fn as_file_mut(&mut self) -> &mut F {
839
4.14k
        &mut self.file
840
4.14k
    }
841
842
    /// Turn this named temporary file into an "unnamed" temporary file as if you
843
    /// had constructed it with [`tempfile()`].
844
    ///
845
    /// The underlying file will be removed from the filesystem but the returned [`File`]
846
    /// can still be read/written.
847
0
    pub fn into_file(self) -> F {
848
0
        self.file
849
0
    }
850
851
    /// Closes the file, leaving only the temporary file path.
852
    ///
853
    /// This is useful when another process must be able to open the temporary
854
    /// file.
855
0
    pub fn into_temp_path(self) -> TempPath {
856
0
        self.path
857
0
    }
858
859
    /// Converts the named temporary file into its constituent parts.
860
    ///
861
    /// Note: When the path is dropped, the underlying file will be removed from the filesystem but
862
    /// the returned [`File`] can still be read/written.
863
0
    pub fn into_parts(self) -> (F, TempPath) {
864
0
        (self.file, self.path)
865
0
    }
866
867
    /// Creates a `NamedTempFile` from its constituent parts.
868
    ///
869
    /// This can be used with [`NamedTempFile::into_parts`] to reconstruct the
870
    /// `NamedTempFile`.
871
0
    pub fn from_parts(file: F, path: TempPath) -> Self {
872
0
        Self { file, path }
873
0
    }
874
}
875
876
impl NamedTempFile<File> {
877
    /// Securely reopen the temporary file.
878
    ///
879
    /// This function is useful when you need multiple independent handles to
880
    /// the same file. It's perfectly fine to drop the original `NamedTempFile`
881
    /// while holding on to `File`s returned by this function; the `File`s will
882
    /// remain usable. However, they may not be nameable.
883
    ///
884
    /// # Errors
885
    ///
886
    /// If the file cannot be reopened, `Err` is returned.
887
    ///
888
    /// # Security
889
    ///
890
    /// Unlike `File::open(my_temp_file.path())`, `NamedTempFile::reopen()`
891
    /// guarantees that the re-opened file is the _same_ file, even in the
892
    /// presence of pathological temporary file cleaners.
893
    ///
894
    /// # Examples
895
    ///
896
    /// ```no_run
897
    /// use tempfile::NamedTempFile;
898
    ///
899
    /// let file = NamedTempFile::new()?;
900
    ///
901
    /// let another_handle = file.reopen()?;
902
    /// # Ok::<(), std::io::Error>(())
903
    /// ```
904
0
    pub fn reopen(&self) -> io::Result<File> {
905
0
        imp::reopen(self.as_file(), NamedTempFile::path(self))
906
0
            .with_err_path(|| NamedTempFile::path(self))
907
0
    }
908
}
909
910
impl<F: Read> Read for NamedTempFile<F> {
911
0
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
912
0
        self.as_file_mut().read(buf).with_err_path(|| self.path())
913
0
    }
914
915
0
    fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
916
0
        self.as_file_mut()
917
0
            .read_vectored(bufs)
918
0
            .with_err_path(|| self.path())
919
0
    }
920
921
0
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
922
0
        self.as_file_mut()
923
0
            .read_to_end(buf)
924
0
            .with_err_path(|| self.path())
925
0
    }
926
927
0
    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
928
0
        self.as_file_mut()
929
0
            .read_to_string(buf)
930
0
            .with_err_path(|| self.path())
931
0
    }
932
933
0
    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
934
0
        self.as_file_mut()
935
0
            .read_exact(buf)
936
0
            .with_err_path(|| self.path())
937
0
    }
938
}
939
940
impl Read for &NamedTempFile<File> {
941
0
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
942
0
        self.as_file().read(buf).with_err_path(|| self.path())
943
0
    }
944
945
0
    fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
946
0
        self.as_file()
947
0
            .read_vectored(bufs)
948
0
            .with_err_path(|| self.path())
949
0
    }
950
951
0
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
952
0
        self.as_file()
953
0
            .read_to_end(buf)
954
0
            .with_err_path(|| self.path())
955
0
    }
956
957
0
    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
958
0
        self.as_file()
959
0
            .read_to_string(buf)
960
0
            .with_err_path(|| self.path())
961
0
    }
962
963
0
    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
964
0
        self.as_file().read_exact(buf).with_err_path(|| self.path())
965
0
    }
966
}
967
968
impl<F: Write> Write for NamedTempFile<F> {
969
0
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
970
0
        self.as_file_mut().write(buf).with_err_path(|| self.path())
971
0
    }
972
    #[inline]
973
0
    fn flush(&mut self) -> io::Result<()> {
974
0
        self.as_file_mut().flush().with_err_path(|| self.path())
975
0
    }
976
977
0
    fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
978
0
        self.as_file_mut()
979
0
            .write_vectored(bufs)
980
0
            .with_err_path(|| self.path())
981
0
    }
982
983
2.07k
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
984
2.07k
        self.as_file_mut()
985
2.07k
            .write_all(buf)
986
2.07k
            .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}
987
2.07k
    }
Unexecuted instantiation: <tempfile::file::NamedTempFile<_> as std::io::Write>::write_all
<tempfile::file::NamedTempFile as std::io::Write>::write_all
Line
Count
Source
983
2.07k
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
984
2.07k
        self.as_file_mut()
985
2.07k
            .write_all(buf)
986
2.07k
            .with_err_path(|| self.path())
987
2.07k
    }
988
989
0
    fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
990
0
        self.as_file_mut()
991
0
            .write_fmt(fmt)
992
0
            .with_err_path(|| self.path())
993
0
    }
994
}
995
996
impl Write for &NamedTempFile<File> {
997
0
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
998
0
        self.as_file().write(buf).with_err_path(|| self.path())
999
0
    }
1000
    #[inline]
1001
0
    fn flush(&mut self) -> io::Result<()> {
1002
0
        self.as_file().flush().with_err_path(|| self.path())
1003
0
    }
1004
1005
0
    fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
1006
0
        self.as_file()
1007
0
            .write_vectored(bufs)
1008
0
            .with_err_path(|| self.path())
1009
0
    }
1010
1011
0
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
1012
0
        self.as_file().write_all(buf).with_err_path(|| self.path())
1013
0
    }
1014
1015
0
    fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
1016
0
        self.as_file().write_fmt(fmt).with_err_path(|| self.path())
1017
0
    }
1018
}
1019
1020
impl<F: Seek> Seek for NamedTempFile<F> {
1021
0
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
1022
0
        self.as_file_mut().seek(pos).with_err_path(|| self.path())
1023
0
    }
1024
}
1025
1026
impl Seek for &NamedTempFile<File> {
1027
0
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
1028
0
        self.as_file().seek(pos).with_err_path(|| self.path())
1029
0
    }
1030
}
1031
1032
#[cfg(any(unix, target_os = "wasi"))]
1033
impl<F: AsFd> AsFd for NamedTempFile<F> {
1034
0
    fn as_fd(&self) -> BorrowedFd<'_> {
1035
0
        self.as_file().as_fd()
1036
0
    }
1037
}
1038
1039
#[cfg(any(unix, target_os = "wasi"))]
1040
impl<F: AsRawFd> AsRawFd for NamedTempFile<F> {
1041
    #[inline]
1042
0
    fn as_raw_fd(&self) -> RawFd {
1043
0
        self.as_file().as_raw_fd()
1044
0
    }
1045
}
1046
1047
#[cfg(windows)]
1048
impl<F: AsHandle> AsHandle for NamedTempFile<F> {
1049
    #[inline]
1050
    fn as_handle(&self) -> BorrowedHandle<'_> {
1051
        self.as_file().as_handle()
1052
    }
1053
}
1054
1055
#[cfg(windows)]
1056
impl<F: AsRawHandle> AsRawHandle for NamedTempFile<F> {
1057
    #[inline]
1058
    fn as_raw_handle(&self) -> RawHandle {
1059
        self.as_file().as_raw_handle()
1060
    }
1061
}
1062
1063
2.07k
pub(crate) fn create_named(
1064
2.07k
    path: PathBuf,
1065
2.07k
    open_options: &mut OpenOptions,
1066
2.07k
    permissions: Option<&std::fs::Permissions>,
1067
2.07k
    keep: bool,
1068
2.07k
) -> io::Result<NamedTempFile> {
1069
2.07k
    imp::create_named(&path, open_options, permissions)
1070
2.07k
        .with_err_path(|| path.clone())
1071
2.07k
        .map(|file| NamedTempFile {
1072
2.07k
            path: TempPath {
1073
2.07k
                path: path.into_boxed_path(),
1074
2.07k
                disable_cleanup: keep,
1075
2.07k
            },
1076
2.07k
            file,
1077
2.07k
        })
1078
2.07k
}