summaryrefslogtreecommitdiffstats
path: root/vendor/tempfile/src/file/imp/unix.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /vendor/tempfile/src/file/imp/unix.rs
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/tempfile/src/file/imp/unix.rs')
-rw-r--r--vendor/tempfile/src/file/imp/unix.rs137
1 files changed, 137 insertions, 0 deletions
diff --git a/vendor/tempfile/src/file/imp/unix.rs b/vendor/tempfile/src/file/imp/unix.rs
new file mode 100644
index 000000000..35b1ddb1e
--- /dev/null
+++ b/vendor/tempfile/src/file/imp/unix.rs
@@ -0,0 +1,137 @@
+use std::env;
+use std::ffi::{CString, OsStr};
+use std::fs::{self, File, OpenOptions};
+use std::io;
+use std::os::unix::ffi::OsStrExt;
+use std::os::unix::fs::{MetadataExt, OpenOptionsExt};
+use std::path::Path;
+use crate::util;
+
+#[cfg(not(target_os = "redox"))]
+use libc::{c_char, c_int, link, rename, unlink};
+
+#[cfg(not(target_os = "redox"))]
+#[inline(always)]
+pub fn cvt_err(result: c_int) -> io::Result<c_int> {
+ if result == -1 {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(result)
+ }
+}
+
+#[cfg(target_os = "redox")]
+#[inline(always)]
+pub fn cvt_err(result: Result<usize, syscall::Error>) -> io::Result<usize> {
+ result.map_err(|err| io::Error::from_raw_os_error(err.errno))
+}
+
+// Stolen from std.
+pub fn cstr(path: &Path) -> io::Result<CString> {
+ CString::new(path.as_os_str().as_bytes())
+ .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "path contained a null"))
+}
+
+pub fn create_named(path: &Path, open_options: &mut OpenOptions) -> io::Result<File> {
+ open_options
+ .read(true)
+ .write(true)
+ .create_new(true)
+ .mode(0o600)
+ .open(path)
+}
+
+fn create_unlinked(path: &Path) -> io::Result<File> {
+ let tmp;
+ // shadow this to decrease the lifetime. It can't live longer than `tmp`.
+ let mut path = path;
+ if !path.is_absolute() {
+ let cur_dir = env::current_dir()?;
+ tmp = cur_dir.join(path);
+ path = &tmp;
+ }
+
+ let f = create_named(path, &mut OpenOptions::new())?;
+ // don't care whether the path has already been unlinked,
+ // but perhaps there are some IO error conditions we should send up?
+ let _ = fs::remove_file(path);
+ Ok(f)
+}
+
+#[cfg(target_os = "linux")]
+pub fn create(dir: &Path) -> io::Result<File> {
+ use libc::{EISDIR, ENOENT, EOPNOTSUPP, O_EXCL, O_TMPFILE};
+ OpenOptions::new()
+ .read(true)
+ .write(true)
+ .custom_flags(O_TMPFILE | O_EXCL) // do not mix with `create_new(true)`
+ .open(dir)
+ .or_else(|e| {
+ match e.raw_os_error() {
+ // These are the three "not supported" error codes for O_TMPFILE.
+ Some(EOPNOTSUPP) | Some(EISDIR) | Some(ENOENT) => create_unix(dir),
+ _ => Err(e),
+ }
+ })
+}
+
+#[cfg(not(target_os = "linux"))]
+pub fn create(dir: &Path) -> io::Result<File> {
+ create_unix(dir)
+}
+
+fn create_unix(dir: &Path) -> io::Result<File> {
+ util::create_helper(
+ dir,
+ OsStr::new(".tmp"),
+ OsStr::new(""),
+ crate::NUM_RAND_CHARS,
+ |path| create_unlinked(&path),
+ )
+}
+
+pub fn reopen(file: &File, path: &Path) -> io::Result<File> {
+ let new_file = OpenOptions::new().read(true).write(true).open(path)?;
+ let old_meta = file.metadata()?;
+ let new_meta = new_file.metadata()?;
+ if old_meta.dev() != new_meta.dev() || old_meta.ino() != new_meta.ino() {
+ return Err(io::Error::new(
+ io::ErrorKind::NotFound,
+ "original tempfile has been replaced",
+ ));
+ }
+ Ok(new_file)
+}
+
+#[cfg(not(target_os = "redox"))]
+pub fn persist(old_path: &Path, new_path: &Path, overwrite: bool) -> io::Result<()> {
+ unsafe {
+ let old_path = cstr(old_path)?;
+ let new_path = cstr(new_path)?;
+ if overwrite {
+ cvt_err(rename(
+ old_path.as_ptr() as *const c_char,
+ new_path.as_ptr() as *const c_char,
+ ))?;
+ } else {
+ cvt_err(link(
+ old_path.as_ptr() as *const c_char,
+ new_path.as_ptr() as *const c_char,
+ ))?;
+ // Ignore unlink errors. Can we do better?
+ // On recent linux, we can use renameat2 to do this atomically.
+ let _ = unlink(old_path.as_ptr() as *const c_char);
+ }
+ Ok(())
+ }
+}
+
+#[cfg(target_os = "redox")]
+pub fn persist(old_path: &Path, new_path: &Path, overwrite: bool) -> io::Result<()> {
+ // XXX implement when possible
+ Err(io::Error::from_raw_os_error(syscall::ENOSYS))
+}
+
+pub fn keep(_: &Path) -> io::Result<()> {
+ Ok(())
+}