Save notes whose body is empty - #33
Merged
Merged
Conversation
A note with an empty body is stored as a zero-length file. Foundation returns a NULL buffer pointer for zero-length NSData, so once such a note was read back from disk and its source baseline cached, -sourceDataReturningError: returned that data unchanged and FSRefWriteData rejected the NULL pointer with paramErr. The note failed to save with "Changed notes could not be saved because a parameter was invalid", and the temporary file created for the atomic swap was left behind in the notes directory. The failure appeared only after a relaunch, because a note created in the current session has no cached source baseline, and it affected several notes at once during any pass that rewrites every note, such as a storage-format change. Treat a zero-length write as valid in FSRefWriteData, which also covers the export path, and skip the unchanged-source fast path when the cached data is empty so a NULL pointer never reaches a writer. Claude-Session: https://claude.ai/code/session_01W5dVNP811hKcLKUmJHD1FG
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Saving a note with an empty body failed with a modal alert:
That text is OSStatus -50 (
paramErr), raised by-noteDidNotWrite:errorCode:. Each failure also orphaned a zero-length temporary file in the notes directory.Cause
A note with an empty body is stored as a zero-length file, and Foundation returns a NULL buffer pointer for zero-length
NSData:Once such a note was read back from disk,
-rememberSourceBaselineData:encoding:cached that NULL-pointer data. On the next save, the unchanged-source fast path in-sourceDataReturningError:returned it verbatim instead of re-encoding, andFSRefWriteDatarejected it:Traced directly:
The temporary file is created before the write, so a failure leaves it behind — which is the signature these failures leave in a notes directory.
Two conditions hid this. A note created in the current session has no cached source baseline, so it re-encodes and saves fine; the failure needs a relaunch first. And it affects every empty-body note at once during any pass that rewrites all notes, such as a storage-format change, rather than a single deliberate save.
The earlier write path always built data with
dataUsingEncoding:, which returns a non-NULL pointer for an empty string, so this arrived with the source-editing work in60e0333.Fix
Sources/Utilities/BufferUtils.c— a zero-length write is valid, so only a missing buffer with bytes to write is an error. This also covers the export path, which passes[formattedData bytes]and had the same latent failure.Sources/Model/NoteObject.m— skip the unchanged-source fast path when the cached data is empty, so a NULL pointer never reaches a writer.Testing
New suite
Tests/Regression/empty-source-write/, registered inTests/run-regression-tests.py(18 checks):FSRefWriteDataaccepts a zero-length write with a NULL buffer, and still rejects a NULL buffer with bytes to write, and a missingFSRefVerified against a copy of a real library with five empty-body notes: 5 failures and 5 orphaned temporary files before, 0 and 0 after. Reverting either guard and rebuilding fails the suite (
FAIL: zero-length write with a NULL buffer succeeds), so the check cannot pass vacuously.Ran on macOS 13.7.8, Intel Development build.
https://claude.ai/code/session_01W5dVNP811hKcLKUmJHD1FG