Add FileTransfer (drag & drop / copy & paste files)

Host->Guest is easy; Guest->Host is not there yet because we have to do
something for the (O_PATH) fd passing such as converting to inode numbers
and getting an O_PATH fd back through the VMM, which requires modifying
libkrun/muvm to have a connection channel.. Or we should switch this from
vsock to a virtgpu channel where it would be easier to handle.
This commit is contained in:
Val Packett 2026-02-06 00:31:15 -03:00
parent 762dd2dd84
commit 2561342e0c
5 changed files with 216 additions and 20 deletions

View file

@ -53,6 +53,7 @@ impl FileChooser {
docs: self.docs.clone(),
guest_root: self.guest_root.clone(),
for_save: false,
persistent: true,
directory: options.get_as("directory")?.unwrap_or(false),
})
.perform(async || self.host.open_file(parent_window, title, options).await)
@ -73,6 +74,7 @@ impl FileChooser {
docs: self.docs.clone(),
guest_root: self.guest_root.clone(),
for_save: true,
persistent: true,
directory: false,
})
.perform(async || self.host.save_file(parent_window, title, options).await)
@ -93,6 +95,7 @@ impl FileChooser {
docs: self.docs.clone(),
guest_root: self.guest_root.clone(),
for_save: true,
persistent: true,
directory: false,
})
.perform(async || self.host.save_files(parent_window, title, options).await)
@ -106,11 +109,13 @@ impl FileChooser {
}
}
struct FileTransformer {
docs: DocumentsProxy<'static>,
guest_root: PathBuf,
for_save: bool,
directory: bool,
#[derive(Clone)]
pub struct FileTransformer {
pub docs: DocumentsProxy<'static>,
pub guest_root: PathBuf,
pub for_save: bool,
pub persistent: bool,
pub directory: bool,
}
// ref: send_response_in_thread_func
@ -134,6 +139,14 @@ impl ResultTransformer for FileTransformer {
.async_map(|u| self.add_path_as_doc(u))
.await
.flatten()
.map(|path| match url::Url::from_file_path(&path) {
Ok(url) => Some(url.to_string()),
Err(err) => {
warn!(?err, ?path, "could not make url from returned path");
None
}
})
.flatten()
.collect::<Vec<_>>();
results.insert("uris", guest_uris.into());
@ -150,7 +163,7 @@ const DIRECTORY: u32 = 1 << 3;
// https://github.com/flatpak/xdg-desktop-portal/blob/10e712e06aa8eb9cd0e59c73c5be62ba53e981a4/src/xdp-documents.c#L71
impl FileTransformer {
async fn add_path_as_doc(&self, path: PathBuf) -> Option<String> {
pub async fn add_path_as_doc(&self, path: PathBuf) -> Option<PathBuf> {
use rustix::fs::{Mode, OFlags};
let o_path_fd = match rustix::fs::open(
@ -166,8 +179,8 @@ impl FileTransformer {
};
let flags = REUSE_EXISTING
| PERSISTENT
| AS_NEEDED_BY_APP
| if self.persistent { PERSISTENT } else { 0 }
| if self.directory { DIRECTORY } else { 0 };
// XXX: portal impl can return writable=false but host frontend does not pass that back..
@ -212,14 +225,7 @@ impl FileTransformer {
return None;
}
};
let path = self.guest_root.join(doc_id).join(filename);
match url::Url::from_file_path(&path) {
Ok(url) => Some(url.to_string()),
Err(err) => {
warn!(?err, ?path, "could not make url from returned path");
None
}
}
Some(self.guest_root.join(doc_id).join(filename))
}
}