Skip to content

fix(copy): file-to-file extraction for copy_in/copy_out#261

Merged
DorianZheng merged 1 commit intomainfrom
fix/copy-in-file-to-file-238
Feb 13, 2026
Merged

fix(copy): file-to-file extraction for copy_in/copy_out#261
DorianZheng merged 1 commit intomainfrom
fix/copy-in-file-to-file-238

Conversation

@DorianZheng
Copy link
Copy Markdown
Member

Summary

Fixes #238copy_in("file.py", "/workspace/script.py") created a directory named script.py instead of copying the file.

  • Add mode-aware tar extraction (FileToFile vs IntoDirectory) to both guest upload and host download paths
  • Inspect tar contents and destination state to choose extraction mode, following Docker cp semantics
  • Add 14 unit tests covering all extraction mode combinations and edge cases
  • Add Python example (Example 4) demonstrating file-to-file copy, rename, and directory semantics

Behavior matrix

Source Destination Dest state Result
file foo.py /workspace/script.py doesn't exist /workspace/script.py (file)
file foo.py /workspace/bar.py doesn't exist /workspace/bar.py (renamed)
file foo.py /workspace/script.py exists as file overwrites file
file foo.py /workspace/scripts exists as dir /workspace/scripts/foo.py
file foo.py /workspace/ any /workspace/foo.py
dir mydir/ /workspace/mydir any unchanged (dir copy)

Key insight

tar::Entry::unpack(dest) writes directly to dest (ignoring the tar entry name), while tar::Archive::unpack(dest) treats dest as a parent directory. The fix uses the former for single-file-to-file-path cases.

Test plan

  • cargo test -p boxlite --no-default-features --lib — 14 tests pass (including regression test for copy_in creates directory when destination is a file path #238)
  • cargo clippy -p boxlite --no-default-features --lib -- -D warnings — clean
  • cargo fmt --check — clean
  • Manual integration test: copy_in("script.py", "/workspace/script.py") creates a file
  • Manual test: copy_in("foo.py", "/workspace/bar.py") renames correctly
  • Manual test: copy_in("foo.py", "/workspace/") copies into directory

copy_in("file.py", "/workspace/script.py") previously created a
directory named script.py instead of copying the file. The root cause
was that both guest upload and host download unconditionally treated
the destination as a directory to extract into.

Add mode-aware extraction that inspects tar contents and destination
state to choose between two modes:
- FileToFile: single regular file in tar + dest is not trailing '/' +
  dest is not an existing directory → use entry.unpack(dest)
- IntoDirectory: everything else → archive.unpack(dest) (unchanged)

This follows Docker cp semantics: trailing slash forces directory mode,
existing directory receives files inside it, and non-existent non-slash
paths with single-file source create a file at that exact path.
@DorianZheng DorianZheng merged commit 9272e38 into main Feb 13, 2026
14 checks passed
@DorianZheng DorianZheng deleted the fix/copy-in-file-to-file-238 branch February 13, 2026 16:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

copy_in creates directory when destination is a file path

1 participant