xpc: better file descriptor handling
This commit is contained in:
@@ -113,46 +113,13 @@ impl XpcAgent {
|
|||||||
let response = rt_conn.block_on(super::rpc::dispatch(&agent_conn, &conns_for_handler, client, &map));
|
let response = rt_conn.block_on(super::rpc::dispatch(&agent_conn, &conns_for_handler, client, &map));
|
||||||
let reply = xpc_sys::xpc_dictionary_create_reply(msg);
|
let reply = xpc_sys::xpc_dictionary_create_reply(msg);
|
||||||
if !reply.is_null() {
|
if !reply.is_null() {
|
||||||
use std::ffi::CString as StdCString;
|
|
||||||
use std::os::fd::AsRawFd;
|
|
||||||
|
|
||||||
// Precompute optional fd_path instruction from the message map
|
|
||||||
let mut maybe_fd_path: Option<String> = None;
|
|
||||||
if let Message::Dictionary(ref resp_map) = response {
|
|
||||||
let attach = super::util::dict_get_str(resp_map, "attach_fd").unwrap_or_default() == "true";
|
|
||||||
if attach {
|
|
||||||
maybe_fd_path = super::util::dict_get_str(resp_map, "fd_path");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let payload = message_to_xpc_object(response);
|
let payload = message_to_xpc_object(response);
|
||||||
let apply_block = ConcreteBlock::new(move |key: *const c_char, value: xpc_sys::xpc_object_t| {
|
let apply_block = ConcreteBlock::new(move |key: *const c_char, value: xpc_sys::xpc_object_t| {
|
||||||
xpc_sys::xpc_dictionary_set_value(reply, key, value);
|
xpc_sys::xpc_dictionary_set_value(reply, key, value);
|
||||||
})
|
})
|
||||||
.copy();
|
.copy();
|
||||||
|
|
||||||
xpc_sys::xpc_dictionary_apply(payload, apply_block.deref() as *const _ as *mut _);
|
|
||||||
|
|
||||||
// Optional FD attachment if requested by response
|
xpc_sys::xpc_dictionary_apply(payload, apply_block.deref() as *const _ as *mut _);
|
||||||
if let Some(fd_path) = maybe_fd_path {
|
|
||||||
match std::fs::OpenOptions::new().read(true).open(&fd_path) {
|
|
||||||
Ok(file) => {
|
|
||||||
let raw_fd = file.as_raw_fd();
|
|
||||||
unsafe {
|
|
||||||
let fd_obj = xpc_sys::xpc_fd_create(raw_fd);
|
|
||||||
let key = StdCString::new("fd").unwrap();
|
|
||||||
xpc_sys::xpc_dictionary_set_value(reply, key.as_ptr(), fd_obj);
|
|
||||||
// fd_obj is retained by reply; release our reference
|
|
||||||
xpc_sys::xpc_release(fd_obj);
|
|
||||||
}
|
|
||||||
// Keep file alive until after send
|
|
||||||
std::mem::forget(file);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
log::warn!(target: LOG_TARGET, "Failed to open fd_path '{}': {}", fd_path, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
xpc_sys::xpc_connection_send_message(client, reply);
|
xpc_sys::xpc_connection_send_message(client, reply);
|
||||||
xpc_sys::xpc_release(payload);
|
xpc_sys::xpc_release(payload);
|
||||||
|
|||||||
@@ -303,7 +303,7 @@ pub async fn dispatch(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenAttachmentFd (attach file descriptor in reply)
|
// OpenAttachmentFd (return file descriptor in reply)
|
||||||
"OpenAttachmentFd" => {
|
"OpenAttachmentFd" => {
|
||||||
let args = match get_dictionary_field(root, "arguments") {
|
let args = match get_dictionary_field(root, "arguments") {
|
||||||
Some(a) => a,
|
Some(a) => a,
|
||||||
@@ -322,15 +322,25 @@ pub async fn dispatch(
|
|||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(attachment) => {
|
Ok(attachment) => {
|
||||||
let path = attachment.get_path_for_preview(preview);
|
use std::os::fd::AsRawFd;
|
||||||
let mut reply: XpcMap = HashMap::new();
|
|
||||||
|
|
||||||
// The agent resolves fd_path to a file descriptor and returns it in the reply
|
|
||||||
dict_put_str(&mut reply, "type", "OpenAttachmentFdResponse");
|
|
||||||
dict_put_str(&mut reply, "fd_path", &path.to_string_lossy());
|
|
||||||
dict_put_str(&mut reply, "attach_fd", "true");
|
|
||||||
|
|
||||||
Message::Dictionary(reply)
|
let path = attachment.get_path_for_preview(preview);
|
||||||
|
match std::fs::OpenOptions::new().read(true).open(&path) {
|
||||||
|
Ok(file) => {
|
||||||
|
let fd = file.as_raw_fd();
|
||||||
|
|
||||||
|
// Keep file alive until after conversion to XPC
|
||||||
|
std::mem::forget(file);
|
||||||
|
|
||||||
|
// Return file descriptor in reply
|
||||||
|
let mut reply: XpcMap = HashMap::new();
|
||||||
|
dict_put_str(&mut reply, "type", "OpenAttachmentFdResponse");
|
||||||
|
reply.insert(cstr("fd"), Message::Fd(fd));
|
||||||
|
|
||||||
|
Message::Dictionary(reply)
|
||||||
|
}
|
||||||
|
Err(e) => make_error_reply("OpenFailed", &format!("{}", e)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(e) => make_error_reply("DaemonError", &format!("{}", e)),
|
Err(e) => make_error_reply("DaemonError", &format!("{}", e)),
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user