Skip to content

Conversation

@GomesGoncalo
Copy link
Contributor

Detect symlinks in prompt_file() using fs::symlink_metadata() and handle them differently:

  • InteractiveMode::Always should still prompt with "remove symbolic link ...?".
  • For all other interactive modes, do not follow the symlink target or use the target's permissions to decide a write-protected prompt.

Adds a unit test test_symlink_not_write_protected_prompt to verify that a symlink to a read-only file is not treated as a write-protected regular file.

Closes #10222

@GomesGoncalo GomesGoncalo force-pushed the goncalo.gomes/rm-symlink-behaviour branch 2 times, most recently from f3f691e to aad33db Compare January 14, 2026 13:30
@codspeed-hq
Copy link

codspeed-hq bot commented Jan 14, 2026

CodSpeed Performance Report

Merging this PR will improve performance by 4.84%

Comparing GomesGoncalo:goncalo.gomes/rm-symlink-behaviour (d479e9b) with main (c498595)

Summary

⚡ 3 improved benchmarks
✅ 279 untouched benchmarks
⏩ 38 skipped benchmarks1

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation rm_multiple_files 2.2 ms 2.1 ms +4.84%
Memory du_wide_tree[(5000, 500)] 1.2 MB 1.2 MB +3.54%
Memory cp_large_file[16] 119.4 KB 115.2 KB +3.64%

Footnotes

  1. 38 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@GomesGoncalo
Copy link
Contributor Author

GomesGoncalo commented Jan 14, 2026

CodSpeed Performance Report

Merging this PR will degrade performance by 4.57%

Comparing GomesGoncalo:goncalo.gomes/rm-symlink-behaviour (aad33db) with main (fd9157a)

Summary

❌ 1 regressed benchmark ✅ 140 untouched benchmarks ⏩ 38 skipped benchmarks1

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
❌ Simulation rm_multiple_files 2.2 ms 2.4 ms -4.57%

Footnotes

1. 38 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, [click here and archive them to remove them from the performance reports](https://codspeed.io/uutils/coreutils/branches/GomesGoncalo%3Agoncalo.gomes%2Frm-symlink-behaviour?sectionId=benchmark-comparison-section-baseline-result-skipped&utm_source=github&utm_medium=comment&utm_content=archive). [↩](#user-content-fnref-skipped-65dfc430c8cce12c4551dab4f7d2efc4)
image

looks like entirely related to querying symlink metadata, I tried reversing the logic but found the branch needs to be always taken to keep the functionality

@GomesGoncalo GomesGoncalo force-pushed the goncalo.gomes/rm-symlink-behaviour branch 2 times, most recently from 6ef66b5 to c2a1956 Compare January 15, 2026 10:33
ChrisDryden
ChrisDryden previously approved these changes Jan 15, 2026
@ChrisDryden
Copy link
Collaborator

I'm trying to see if theres a way to deduplicate the metadata call so that theres no performance regression, I think it should be possible only have one call

}
}

let Ok(metadata) = fs::metadata(path) else {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For non-symlinks, fs::symlink_metadata is the same as fs::metadata, you should be able to combine the in a way to only have to call fs::symlink_metadata once and reuse that for later. Maybe if you move this above 803 and change it to symlink_metadata you can use metadata.is_symlink() and it means theres only one stat each time this function is called.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's a good idea, I tested and it still worked, should behave better now

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that even improves performance slightly

@ChrisDryden ChrisDryden dismissed their stale review January 17, 2026 18:12

Re-evaluating after double checking the performance regressions

@GomesGoncalo GomesGoncalo force-pushed the goncalo.gomes/rm-symlink-behaviour branch from c2a1956 to b264abb Compare January 17, 2026 21:05
GNU rm does not check for write-protection on symbolic links; it
instead prompts to "remove symbolic link" regardless of the link's
permissions or its target's status.

This change:
- Ensures `prompt_file` checks for symlinks specifically using
  `symlink_metadata`, avoiding the incorrect "write-protected" prompt.
- Refactors permission checks into `is_writable_metadata` to allow
  using the already-fetched metadata, which also optimizes performance
  by reducing redundant `stat` calls.
- Updates `prompt_file_permission_readonly` to operate on metadata directly.
@GomesGoncalo GomesGoncalo force-pushed the goncalo.gomes/rm-symlink-behaviour branch from b264abb to d479e9b Compare January 17, 2026 21:06
@github-actions
Copy link

GNU testsuite comparison:

Congrats! The gnu test tests/basenc/bounded-memory is now passing!

@sylvestre sylvestre merged commit fc17efe into uutils:main Jan 17, 2026
157 checks passed
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.

rm symlink asks confirmation when its source file is write-protected

3 participants