aboutsummaryrefslogtreecommitdiff
path: root/src/platform/linux.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform/linux.rs')
-rw-r--r--src/platform/linux.rs77
1 files changed, 69 insertions, 8 deletions
diff --git a/src/platform/linux.rs b/src/platform/linux.rs
index 4d2ed049..8e5ad7a6 100644
--- a/src/platform/linux.rs
+++ b/src/platform/linux.rs
@@ -4,7 +4,10 @@ use std::{
process::{Command, Stdio},
};
-use super::{ClipboardCommand, ClipboardImage, ForegroundJob, ForegroundProcess, Signal};
+use super::{
+ read_limited_reader, ClipboardCommand, ClipboardImage, ForegroundJob, ForegroundProcess,
+ LimitedRead, Signal,
+};
/// Collect the foreground terminal job for a given child PID.
pub fn foreground_job(child_pid: u32) -> Option<ForegroundJob> {
@@ -221,17 +224,53 @@ fn run_notification_command(mut command: Command) -> std::io::Result<bool> {
}
fn read_clipboard_image_with_command(program: &str, args: &[&str]) -> Option<Vec<u8>> {
- let output = Command::new(program)
- .args(args)
+ let mut command = Command::new(program);
+ command.args(args);
+ read_clipboard_image_with_spawned_command(command)
+}
+
+fn read_clipboard_image_with_spawned_command(command: Command) -> Option<Vec<u8>> {
+ read_clipboard_image_with_spawned_command_max(
+ command,
+ crate::server::protocol::MAX_CLIPBOARD_IMAGE_PAYLOAD,
+ )
+}
+
+fn read_clipboard_image_with_spawned_command_max(
+ mut command: Command,
+ max_bytes: usize,
+) -> Option<Vec<u8>> {
+ let mut child = command
.stdin(Stdio::null())
+ .stdout(Stdio::piped())
.stderr(Stdio::null())
- .output()
+ .spawn()
.ok()?;
+ let stdout = child.stdout.take()?;
+
+ let read = match read_limited_reader(stdout, max_bytes) {
+ Ok(read) => read,
+ Err(_) => {
+ let _ = child.kill();
+ let _ = child.wait();
+ return None;
+ }
+ };
- if output.status.success() && !output.stdout.is_empty() {
- Some(output.stdout)
- } else {
- None
+ if read == LimitedRead::Oversized {
+ let _ = child.kill();
+ let _ = child.wait();
+ return None;
+ }
+
+ let status = child.wait().ok()?;
+ if !status.success() {
+ return None;
+ }
+
+ match read {
+ LimitedRead::Complete(bytes) => Some(bytes),
+ LimitedRead::Empty | LimitedRead::Oversized => None,
}
}
@@ -330,6 +369,28 @@ mod tests {
}
#[test]
+ fn read_clipboard_image_with_spawned_command_reads_under_limit() {
+ let mut command = Command::new("sh");
+ command.arg("-c").arg("printf image");
+
+ assert_eq!(
+ read_clipboard_image_with_spawned_command_max(command, 16),
+ Some(b"image".to_vec())
+ );
+ }
+
+ #[test]
+ fn read_clipboard_image_with_spawned_command_rejects_over_limit() {
+ let mut command = Command::new("sh");
+ command.arg("-c").arg("printf oversized");
+
+ assert_eq!(
+ read_clipboard_image_with_spawned_command_max(command, 4),
+ None
+ );
+ }
+
+ #[test]
fn desktop_notification_separates_option_like_titles() {
let _guard = env_lock().lock().unwrap();
unsafe {