Coverage Report

Created: 2025-12-31 06:16

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