Skip to content

fix: YamlSource leaking file handles and leaving truncated files on crash - #209

Open
DragonL0508 wants to merge 1 commit into
FairyProject:v0.7from
DragonL0508:fix/yaml-source-io
Open

DragonL0508 wants to merge 1 commit into
FairyProject:v0.7from
DragonL0508:fix/yaml-source-io

Conversation

@DragonL0508

Copy link
Copy Markdown
  • Reading: readConfig used Files.lines without closing the stream, so every load kept the file open until GC. On Windows an open file can't be replaced or deleted, so anything that moves a file over a config right after loading it fails with AccessDeniedException.
  • Writing: saveConfiguration overwrote the file in place with Files.write. A crash or kill mid-save leaves a truncated file; if the cut lands at the end of a line the YAML still parses, the missing fields fall back to their defaults on the next load and loadAndSave writes those defaults back, silently losing data. The dump is now written to a temporary file next to the config and moved over it (atomically when the file system supports it). The temporary file is created with Files.write rather than Files.createTempFile, so the config keeps its usual permissions.
  • Charset: the dump was encoded with the platform default charset while Files.lines reads UTF-8, which breaks non-ASCII values on Java < 18 with a non-UTF-8 default (e.g. Windows). It is now always UTF-8.

Tests: YamlSourceFileTest covers a UTF-8 round trip, replacing an existing file without leaving temporary files behind, and creating missing parent directories.

🤖 Generated with Claude Code

…rash

Reading: readConfig used Files.lines without closing the stream, so
every load kept the file open until the stream was garbage collected.
On Windows an open file cannot be replaced or deleted, so anything that
moves a file over a config right after loading it (backups, atomic
replaces, the change below) fails with AccessDeniedException.

Writing: saveConfiguration wrote the file in place with Files.write. A
crash or kill during a save leaves a truncated file; if the cut happens
at the end of a line the YAML still parses, the missing fields fall back
to their defaults on the next load, and loadAndSave writes those
defaults back, silently losing data. The dump is now written to a
temporary file next to the config and moved over it (atomically when
the file system supports it).

The dump was also encoded with the platform default charset while
Files.lines reads UTF-8, which breaks non-ASCII values on Java < 18 with
a non-UTF-8 default charset (e.g. Windows). It is now always UTF-8.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant