]> git.proxmox.com Git - rustc.git/blob - src/vendor/tempfile/src/file/imp/unix.rs
New upstream version 1.28.0~beta.14+dfsg1
[rustc.git] / src / vendor / tempfile / src / file / imp / unix.rs
1 #[cfg(not(target_os = "redox"))]
2 use libc::{c_char, c_int, link, rename, unlink, O_CLOEXEC, O_CREAT, O_EXCL, O_RDWR};
3 use std::ffi::CString;
4 use std::fs::{self, File, OpenOptions};
5 use std::io;
6 use std::os::unix::ffi::OsStrExt;
7 use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
8 use std::path::Path;
9 use util;
10
11 #[cfg(all(lfs_support, target_os = "linux"))]
12 use libc::{fstat64 as fstat, open64 as open, stat64 as stat_t};
13
14 #[cfg(not(any(all(lfs_support, target_os = "linux"), target_os = "redox")))]
15 use libc::{fstat, open, stat as stat_t};
16
17 #[cfg(target_os = "redox")]
18 use syscall::{self, fstat, open, Stat as stat_t, O_CLOEXEC, O_CREAT, O_EXCL, O_RDWR};
19
20 #[cfg(not(target_os = "redox"))]
21 #[inline(always)]
22 pub fn cvt_err(result: c_int) -> io::Result<c_int> {
23 if result == -1 {
24 Err(io::Error::last_os_error())
25 } else {
26 Ok(result)
27 }
28 }
29
30 #[cfg(target_os = "redox")]
31 #[inline(always)]
32 pub fn cvt_err(result: Result<usize, syscall::Error>) -> io::Result<usize> {
33 result.map_err(|err| io::Error::from_raw_os_error(err.errno))
34 }
35
36 // Stolen from std.
37 pub fn cstr(path: &Path) -> io::Result<CString> {
38 CString::new(path.as_os_str().as_bytes())
39 .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "path contained a null"))
40 }
41
42 #[cfg(not(target_os = "redox"))]
43 pub fn create_named(path: &Path) -> io::Result<File> {
44 unsafe {
45 let path = cstr(path)?;
46 let fd = cvt_err(open(
47 path.as_ptr() as *const c_char,
48 O_CLOEXEC | O_EXCL | O_RDWR | O_CREAT,
49 0o600,
50 ))?;
51 Ok(FromRawFd::from_raw_fd(fd))
52 }
53 }
54
55 #[cfg(target_os = "redox")]
56 pub fn create_named(path: PathBuf) -> io::Result<File> {
57 unsafe {
58 let fd = cvt_err(open(
59 path.as_os_str().as_bytes(),
60 O_CLOEXEC | O_EXCL | O_RDWR | O_CREAT | 0o600,
61 ))?;
62 Ok(FromRawFd::from_raw_fd(fd))
63 }
64 }
65
66 fn create_unlinked(path: &Path) -> io::Result<File> {
67 let f = create_named(path)?;
68 // don't care whether the path has already been unlinked,
69 // but perhaps there are some IO error conditions we should send up?
70 let _ = fs::remove_file(path);
71 Ok(f)
72 }
73
74 #[cfg(target_os = "linux")]
75 pub fn create(dir: &Path) -> io::Result<File> {
76 use libc::O_TMPFILE;
77 match unsafe {
78 let path = cstr(dir)?;
79 open(
80 path.as_ptr() as *const c_char,
81 O_CLOEXEC | O_EXCL | O_TMPFILE | O_RDWR,
82 0o600,
83 )
84 } {
85 -1 => create_unix(dir),
86 fd => Ok(unsafe { FromRawFd::from_raw_fd(fd) }),
87 }
88 }
89
90 #[cfg(not(target_os = "linux"))]
91 pub fn create(dir: &Path) -> io::Result<File> {
92 create_unix(dir)
93 }
94
95 fn create_unix(dir: &Path) -> io::Result<File> {
96 util::create_helper(dir, ".tmp", "", ::NUM_RAND_CHARS, |path| {
97 create_unlinked(&path)
98 })
99 }
100
101 unsafe fn stat(fd: RawFd) -> io::Result<stat_t> {
102 let mut meta: stat_t = ::std::mem::zeroed();
103 cvt_err(fstat(fd, &mut meta))?;
104 Ok(meta)
105 }
106
107 pub fn reopen(file: &File, path: &Path) -> io::Result<File> {
108 let new_file = OpenOptions::new().read(true).write(true).open(path)?;
109 unsafe {
110 let old_meta = stat(file.as_raw_fd())?;
111 let new_meta = stat(new_file.as_raw_fd())?;
112 if old_meta.st_dev != new_meta.st_dev || old_meta.st_ino != new_meta.st_ino {
113 return Err(io::Error::new(
114 io::ErrorKind::NotFound,
115 "original tempfile has been replaced",
116 ));
117 }
118 Ok(new_file)
119 }
120 }
121
122 #[cfg(not(target_os = "redox"))]
123 pub fn persist(old_path: &Path, new_path: &Path, overwrite: bool) -> io::Result<()> {
124 unsafe {
125 let old_path = cstr(old_path)?;
126 let new_path = cstr(new_path)?;
127 if overwrite {
128 cvt_err(rename(
129 old_path.as_ptr() as *const c_char,
130 new_path.as_ptr() as *const c_char,
131 ))?;
132 } else {
133 cvt_err(link(
134 old_path.as_ptr() as *const c_char,
135 new_path.as_ptr() as *const c_char,
136 ))?;
137 // Ignore unlink errors. Can we do better?
138 // On recent linux, we can use renameat2 to do this atomically.
139 let _ = unlink(old_path.as_ptr() as *const c_char);
140 }
141 Ok(())
142 }
143 }
144
145 #[cfg(target_os = "redox")]
146 pub fn persist(old_path: &Path, new_path: &Path, overwrite: bool) -> io::Result<()> {
147 // XXX implement when possible
148 Err(io::Error::from_raw_os_error(syscall::ENOSYS))
149 }