Skip to content

[IO-879] Restore read-only state after failed deletion - #881

Closed
efegokdemir wants to merge 6 commits into
apache:masterfrom
efegokdemir:codex/IO-879-restore-readonly-on-delete-failure
Closed

efegokdemir wants to merge 6 commits into
apache:masterfrom
efegokdemir:codex/IO-879-restore-readonly-on-delete-failure

Conversation

@efegokdemir

@efegokdemir efegokdemir commented Sep 23, 2026 •

Copy link
Copy Markdown

Summary

Fixes IO-879 by restoring the file's original read-only state and the parent directory's POSIX permissions after an override-enabled deletion attempt. File and parent restoration are attempted independently, and restoration failures are suppressed on the original deletion exception.

Changes

  • Preserve the file's original read-only state and the parent directory's POSIX permissions in both path visitors.
  • Add regressions for successful deletion, failed deletion of writable and read-only files, and parent-permission restoration failure.

Testing

  • Focused visitor tests on macOS with JDK 21: 59 tests, 0 failures or errors, 3 skipped.
  • Full mvn -B -ntp verify: 7,278 tests, 0 failures or errors, 41 skipped; JaCoCo passed.
  • mvn -B -ntp checkstyle:check apache-rat:check: 0 Checkstyle violations; RAT passed.
  • git diff --check: passed.
  • The new regression cases produced 4 failures on the previously published implementation and pass with this change.
  • Windows-specific behaviour was not run locally and remains subject to hosted Windows CI.

AI assistance: OpenAI Codex assisted with implementation and regression tests.

Signed-off-by: Efe Gökdemir <efe@rexcode.co.uk>
@dajiaohuang

Copy link
Copy Markdown

One failure case appears to change the file state: readOnlyCleared records that the override branch ran, not that the file was read-only beforehand. If a writable file is passed with OVERRIDE_READ_ONLY and deletion fails, the finally block calls setReadOnly(file, true), making the previously writable file read-only. Could the original read-only state (or exact attributes) be captured and restored, with a regression test for a writable file whose deletion fails?

AI assistance used.

@garydgregory

Copy link
Copy Markdown
Member

@efegokdemir Please rebase on git master.

@garydgregory garydgregory changed the title IO-879: Restore read-only state after failed deletion [IO-879] Restore read-only state after failed deletion Oct 25, 2026
Restore the original file read-only state and parent POSIX permissions when deletion fails.

Assisted-By: Codex
Restore each file and parent POSIX permissions independently, while retaining the original deletion failure if cleanup also fails. Add regressions for successful deletion, failed deletion and restoration errors.

Assisted-By: OpenAI Codex
Attempt file and parent restoration independently and suppress restoration
errors on the original deletion failure. Keep restoration errors visible
after a successful deletion, with regression coverage for both paths.

Assisted-By: OpenAI Codex
Linux can expose DOS attributes as well as POSIX permissions. Select the
existing POSIX fallback in the successful-deletion visitor regressions,
while retaining real permission changes and deletion. Verify the temporary
writable parent and preserve the exact restored-permission assertions.

No production behavior changes.

Assisted-By: OpenAI Codex
@garydgregory

Copy link
Copy Markdown
Member

@efegokdemir
Thank you for working on IO-879. Restoring the read-only attribute after a failed deletion is the right direction. However, I’m closing this PR in favor of PR #927 that addresses several correctness and testing issues:

  1. The Windows tests do not reliably cause deletion to fail. They mark the parent directory DOS read-only, but Windows does not honor that attribute on directories. That setup does not establish the failure needed to test restoration.

  2. Restoration can change POSIX file permissions. The new isReadOnly() treats missing OWNER_WRITE as read-only, then calls setReadOnly(file, true). That method also adds OWNER_READ, potentially granting a permission the file did not originally have.

  3. Restoring parent permissions after each visitor deletion can interrupt traversal. A parent can become non-writable before a later child directory is deleted, causing AccessDeniedException. I reproduced this behavior and added a regression test.

  4. Attribute-read failures can leave the original problem unresolved. The attribute-reading helpers swallow IOException, so deletion may clear the DOS flag without having saved its original value.

PR #927 reuses DOS restoration logic across the deletion paths, preserves existing POSIX traversal behavior, and avoids clearing DOS state when its original value cannot be read. The tests in PR #927 verify that the flag is cleared during the failing deletion attempt and restored afterward.

Thank you again for the contribution and for helping move this issue forward.

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.

3 participants