aboutsummaryrefslogtreecommitdiff
path: root/src/platform
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform')
-rw-r--r--src/platform/client_state.rs32
-rw-r--r--src/platform/linux.rs2
-rw-r--r--src/platform/macos.rs2
-rw-r--r--src/platform/mod.rs3
-rw-r--r--src/platform/unix_common.rs19
-rw-r--r--src/platform/windows.rs42
6 files changed, 98 insertions, 2 deletions
diff --git a/src/platform/client_state.rs b/src/platform/client_state.rs
new file mode 100644
index 00000000..d339bae8
--- /dev/null
+++ b/src/platform/client_state.rs
@@ -0,0 +1,32 @@
+use std::path::Path;
+
+#[cfg(not(windows))]
+pub(crate) fn create_private_state_file(path: &Path) -> std::io::Result<std::fs::File> {
+ super::create_remote_ssh_config_file(path)
+}
+
+#[cfg(windows)]
+pub(crate) fn create_private_state_file(path: &Path) -> std::io::Result<std::fs::File> {
+ super::windows::create_remote_ssh_config_file(path)
+}
+
+#[cfg(not(windows))]
+pub(crate) fn replace_file(source: &Path, destination: &Path) -> std::io::Result<()> {
+ std::fs::rename(source, destination)
+}
+
+#[cfg(windows)]
+pub(crate) fn replace_file(source: &Path, destination: &Path) -> std::io::Result<()> {
+ super::windows::replace_file(source, destination)
+}
+
+#[cfg(not(windows))]
+pub(crate) fn sync_parent_directory(path: &Path) -> std::io::Result<()> {
+ std::fs::File::open(path)?.sync_all()
+}
+
+#[cfg(windows)]
+pub(crate) fn sync_parent_directory(_path: &Path) -> std::io::Result<()> {
+ // replace_file uses MOVEFILE_WRITE_THROUGH on Windows.
+ Ok(())
+}
diff --git a/src/platform/linux.rs b/src/platform/linux.rs
index 8efe7357..6c09667a 100644
--- a/src/platform/linux.rs
+++ b/src/platform/linux.rs
@@ -17,7 +17,7 @@ pub(crate) use super::unix_common::{
create_remote_ssh_config_file, hostname, local_datetime, remote_bridge_endpoint_path,
remote_private_temp_base, remote_reattach_argument, remote_reattach_program,
remote_ssh_config_paths, set_default_plugin_pane_pwd, status_commands_supported,
- StatusCommandGuard,
+ wait_client_stream_readable, StatusCommandGuard,
};
const WSL_MARKER_ENV_VARS: &[&str] = &["WSL_DISTRO_NAME", "WSL_INTEROP"];
diff --git a/src/platform/macos.rs b/src/platform/macos.rs
index 948468ac..8840c7ed 100644
--- a/src/platform/macos.rs
+++ b/src/platform/macos.rs
@@ -17,7 +17,7 @@ pub(crate) use super::unix_common::{
create_remote_ssh_config_file, hostname, local_datetime, remote_bridge_endpoint_path,
remote_private_temp_base, remote_reattach_argument, remote_reattach_program,
remote_ssh_config_paths, set_default_plugin_pane_pwd, status_commands_supported,
- StatusCommandGuard,
+ wait_client_stream_readable, StatusCommandGuard,
};
const PROC_PGRP_ONLY: u32 = 2;
diff --git a/src/platform/mod.rs b/src/platform/mod.rs
index 4b49b9f7..86a431aa 100644
--- a/src/platform/mod.rs
+++ b/src/platform/mod.rs
@@ -236,6 +236,9 @@ mod unix_common;
#[cfg(unix)]
pub(crate) use unix_common::{begin_cli_output, end_cli_output};
+mod client_state;
+pub(crate) use client_state::{create_private_state_file, replace_file, sync_parent_directory};
+
#[cfg(not(unix))]
pub(crate) fn begin_cli_output() {}
diff --git a/src/platform/unix_common.rs b/src/platform/unix_common.rs
index a7926c22..dff67357 100644
--- a/src/platform/unix_common.rs
+++ b/src/platform/unix_common.rs
@@ -1,5 +1,24 @@
use std::path::{Path, PathBuf};
+pub(crate) fn wait_client_stream_readable(stream: &crate::ipc::LocalStream) -> std::io::Result<()> {
+ use std::os::fd::{AsFd as _, AsRawFd as _};
+ let crate::ipc::LocalStream::UdSocket(stream) = stream;
+ let mut descriptor = libc::pollfd {
+ fd: stream.as_fd().as_raw_fd(),
+ events: libc::POLLIN,
+ revents: 0,
+ };
+ // Bound cancellation latency without polling idle connections hundreds of times per second.
+ let result = unsafe { libc::poll(&mut descriptor, 1, 100) };
+ if result < 0 {
+ let error = std::io::Error::last_os_error();
+ if error.kind() != std::io::ErrorKind::Interrupted {
+ return Err(error);
+ }
+ }
+ Ok(())
+}
+
pub(super) fn read_terminal_grid_size() -> std::io::Result<(u16, u16)> {
crossterm::terminal::window_size().map(|size| (size.columns, size.rows))
}
diff --git a/src/platform/windows.rs b/src/platform/windows.rs
index 1c5c4afb..ce0afedb 100644
--- a/src/platform/windows.rs
+++ b/src/platform/windows.rs
@@ -15,10 +15,52 @@ use std::{
mod clipboard_image;
+pub(crate) fn wait_client_stream_readable(
+ _stream: &crate::ipc::LocalStream,
+) -> std::io::Result<()> {
+ // Sync named pipes have no read timeout. The caller peeks before each read and checks its
+ // cancellation flag between polls, including when a frame arrives in several fragments.
+ std::thread::sleep(Duration::from_millis(2));
+ Ok(())
+}
+
pub(super) fn read_terminal_grid_size() -> std::io::Result<(u16, u16)> {
crossterm::terminal::size()
}
+pub(crate) fn replace_file(
+ source: &std::path::Path,
+ destination: &std::path::Path,
+) -> std::io::Result<()> {
+ use std::os::windows::ffi::OsStrExt;
+ use windows_sys::Win32::Storage::FileSystem::{
+ MoveFileExW, MOVEFILE_REPLACE_EXISTING, MOVEFILE_WRITE_THROUGH,
+ };
+
+ let source = source
+ .as_os_str()
+ .encode_wide()
+ .chain(std::iter::once(0))
+ .collect::<Vec<_>>();
+ let destination = destination
+ .as_os_str()
+ .encode_wide()
+ .chain(std::iter::once(0))
+ .collect::<Vec<_>>();
+ let moved = unsafe {
+ MoveFileExW(
+ source.as_ptr(),
+ destination.as_ptr(),
+ MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH,
+ )
+ };
+ if moved == 0 {
+ Err(std::io::Error::last_os_error())
+ } else {
+ Ok(())
+ }
+}
+
pub(crate) fn set_default_plugin_pane_pwd(
_env: &mut Vec<(String, String)>,
_cwd: &std::path::Path,