Skip to content

Preserve raw filename bytes in trashinfo Path entries#387

Open
SOV710 wants to merge 2 commits into
andreafrancia:masterfrom
SOV710:fix-non-utf8-trashinfo-paths
Open

Preserve raw filename bytes in trashinfo Path entries#387
SOV710 wants to merge 2 commits into
andreafrancia:masterfrom
SOV710:fix-non-utf8-trashinfo-paths

Conversation

@SOV710
Copy link
Copy Markdown

@SOV710 SOV710 commented May 9, 2026

Summary

Fix .trashinfo Path= handling for filenames that are valid filesystem byte sequences but not valid UTF-8.

trash-put can now trash files with names such as b'\xa4-\xc8\xcf-\xc1+\xb8.txt' without losing the original filename bytes.

Bug

trash-put previously percent-encoded Path= from a Python text string. On Python 3, non-UTF-8 filenames are represented with surrogate escapes, and trying to encode those surrogates as UTF-8 can raise UnicodeEncodeError while generating the .trashinfo file.

This means a file can exist on disk and be passable to os.*, but still fail during trash-put.

Reproduction

python3 - <<'PY'
import os

name = b'\xa4-\xc8\xcf-\xc1+\xb8.txt'
fd = os.open(name, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
os.close(fd)
print(os.fsdecode(name))
PY

Then pass the printed filename to:

trash-put ''

Before this PR, trash-put could fail while writing the .trashinfo metadata.

Fix

This PR makes .trashinfo path encoding byte-preserving:

  • Write Path= with os.fsencode(path) followed by byte-based percent encoding.
  • Read Path= with byte-based percent decoding followed by os.fsdecode(...).
  • Use the same helper in both parse_path() and ParseTrashInfo so list/rm/restore parse paths consistently.

This keeps .trashinfo contents UTF-8-compatible while preserving the original filesystem bytes.

Tests

Added coverage for:

  • Formatting non-UTF-8 path bytes into percent-encoded Path=.
  • Parsing percent-encoded Path= back to the original filesystem bytes.
  • ParseTrashInfo callback behavior for non-UTF-8 paths.
  • An e2e trash-put regression test with a real non-UTF-8 filename.

Verified with:

pytest tests/test_trashcli_lib/test_parsing_trashinfo_contents.py
pytest tests/test_put/cmd/e2e
uv run --no-project --with pytest --with flexmock --with six --with psutil --with typing_extensions python -m pytest tests/test_put/cmd/test_put.py

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.

1 participant