Push a local path (file or directory) into a sandbox using tar-over-SSH. When `sandbox_path` is `None`, files are uploaded to the sandbox user's home directory. When uploading a single file to an explicit destination that does not end with `/`, the destination is treated as a file path: the parent directory is created and the file is written with the destination's basename. This matches `cp` /
(
server: &str,
name: &str,
local_path: &Path,
sandbox_path: Option<&str>,
tls: &TlsOptions,
)
| 974 | /// the parent directory is created and the file is written with the |
| 975 | /// destination's basename. This matches `cp` / `scp` semantics. |
| 976 | pub async fn sandbox_sync_up( |
| 977 | server: &str, |
| 978 | name: &str, |
| 979 | local_path: &Path, |
| 980 | sandbox_path: Option<&str>, |
| 981 | tls: &TlsOptions, |
| 982 | ) -> Result<()> { |
| 983 | // When an explicit destination is given and looks like a file path (does |
| 984 | // not end with '/'), split into parent directory + target basename so that |
| 985 | // `mkdir -p` creates the parent and tar extracts the file with the right |
| 986 | // name. |
| 987 | // |
| 988 | // Exception: if splitting would yield "/" as the parent (e.g. the user |
| 989 | // passed "/sandbox"), fall through to directory semantics instead. The |
| 990 | // sandbox user cannot write to "/" and the intent is almost certainly |
| 991 | // "put the file inside /sandbox", not "create a file named sandbox in /". |
| 992 | let local_path_is_file_like = local_upload_path_is_file_like(local_path); |
| 993 | if let Some(path) = sandbox_path |
| 994 | && local_path_is_file_like |
| 995 | && !path.ends_with('/') |
| 996 | { |
| 997 | let (parent, target_name) = split_sandbox_path(path); |
| 998 | if parent != "/" { |
| 999 | return ssh_tar_upload( |
| 1000 | server, |
| 1001 | name, |
| 1002 | Some(parent), |
| 1003 | UploadSource::SinglePath { |
| 1004 | local_path: local_path.to_path_buf(), |
| 1005 | tar_name: target_name.into(), |
| 1006 | }, |
| 1007 | tls, |
| 1008 | ) |
| 1009 | .await; |
| 1010 | } |
| 1011 | } |
| 1012 | |
| 1013 | let tar_name = if local_path_is_file_like { |
| 1014 | local_path |
| 1015 | .file_name() |
| 1016 | .ok_or_else(|| miette::miette!("path has no file name"))? |
| 1017 | .to_os_string() |
| 1018 | } else { |
| 1019 | // For directories, wrap contents under the source basename so uploads |
| 1020 | // land at `<dest>/<dirname>/...` — matches `scp -r` and `cp -r`. Falls |
| 1021 | // back to "." for paths with no meaningful basename (`.`, `/`), which |
| 1022 | // preserves the legacy flatten behavior in those edge cases. |
| 1023 | directory_upload_prefix(local_path) |
| 1024 | }; |
| 1025 | |
| 1026 | ssh_tar_upload( |
| 1027 | server, |
| 1028 | name, |
| 1029 | sandbox_path, |
| 1030 | UploadSource::SinglePath { |
| 1031 | local_path: local_path.to_path_buf(), |
| 1032 | tar_name, |
| 1033 | }, |
no test coverage detected