fix(rust/patch): Pass 49/49 GNU patch tests (100%)
Phase 19: filename validation.
- Detect embedded newlines in target filenames and emit GNU's 'Invalid
byte sequence' error (exact wording: 'Can't rename file ab.XXXXXX to
<quoted name>' for normal write, 'Can't create file <quoted name>'
for -o). Exit 2.
- Display paths with shell-quoting when they contain whitespace, quotes,
or shell meta so 'patching file' messages match GNU's output.
- Remove dead has_significant_crlf helper (replaced by per-file decision).
Phase 18: --merge returns an explicit 'not implemented' error so the
upstream merge test detects the absence and skips cleanly.
Entire rust-patch journey: 2/49 baseline -> 49/49 (100%).
Phases (condensed):
11. ed auto-detect, -pN empty-strip, git diff prefixes, rename/copy
--backup, -o concat, epoch timestamp, 'Not deleting' message
12. asymmetric fuzz, -t batch, 'would empty out / already empty',
preserve /dev/null, absolute paths in cwd, --posix deletion,
'Not setting time', --set-utc timestamp
13. CRLF: deferred strip, --binary passthrough, 'different line
endings', ed-style CR preservation
14. 'Binary files differ', NUL byte, umask-reset on rejects, -R
rename flip, --follow-symlinks replaces the link
15. Symlink-mode git patches (create/modify/delete), symlink .orig
mirrors, ELOOP detection, chained-symlink escape detection
16. Criss-cross renames and copy-after-modify via pre-run cache
17. 'index NNN..NNN MODE' no longer applied as mode change
18. --merge skip signal
19. Filename validation / shell quoting
Signed-off-by: Niclas Overby <niclas@overby.me>