Skip to content

Conversation

@DieterMai
Copy link

@DieterMai DieterMai commented Dec 29, 2025

The previous implementation had the following flaws:

  • On Linux, soft links to directories were followed, causing files outside the workspace to be deleted.
  • On Windows, the read-only flag was not removed explicitly. Before Java 25, this was done implicitly by the File.delete() method. Since Java 25, the flag must be removed before calling File.delete() or Files.delete(). See JDK-8355954.

This PR changes the implementation to:

  • Use the NIO file walker to iterate the root directory.
  • Avoid following symlinks.
  • Remove the Windows read-only flag explicitly.

Resolves #1958

@github-actions
Copy link

github-actions bot commented Dec 30, 2025

Test Results

   771 files  +  148     771 suites  +148   57m 42s ⏱️ + 2m 10s
 3 648 tests ±    0   3 594 ✅ +    2   54 💤 ± 0  0 ❌  - 2 
10 878 runs  +2 665  10 715 ✅ +2 643  163 💤 +24  0 ❌  - 2 

Results for commit 997190e. ± Comparison against base commit e8a7cec.

♻️ This comment has been updated with latest results.

@DieterMai
Copy link
Author

Note I tested this on Linux and Windows. No testing was done on MacOS

Copy link
Contributor

@merks merks left a comment

Choose a reason for hiding this comment

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

I see there exists org.eclipse.osgi.storage.StorageUtil.rm(File, Debug) which also would suffer from the read-only problem, which is a problem I encounter with my SBOM work where I also have similar a utility:

https://github.com/eclipse-cbi/p2repo-sbom/blob/6a5d8b2f81a9db7a953df0b8d42cfeed80ab452a/plugins/org.eclipse.cbi.p2repo.sbom/src/org/eclipse/cbi/p2repo/sbom/IOUtil.java#L40C21-L40C27

Also this utility:

https://github.com/eclipse-cbi/p2repo-aggregator/blob/7cd178676200cc3c86457ce19bd373b764cd53bf/plugins/org.eclipse.cbi.p2repo.util/src/org/eclipse/cbi/p2repo/util/IOUtils.java#L83

This does this the old way:

org.eclipse.help.internal.search.SearchIndex.deleteDir(File)

The above is just an observation of how many places solve this problem with "duplicate" code...

@@ -0,0 +1,134 @@
/*******************************************************************************
* Copyright (c) 2000, 2020 IBM Corporation and others.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm curious why this copyright with these dates? Did you copy this from somewhere?

Copy link
Author

Choose a reason for hiding this comment

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

copy/past

Copy link
Contributor

Choose a reason for hiding this comment

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

If you copied the code that's one thing to copy over the license of that code, but copying a copyright header from some other code is just a template for how a copyright should look. If you wrote the code, it's your copyright and the date is now.

Copy link
Author

Choose a reason for hiding this comment

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

I changed the copyright header.

// only use the root content for progress. anything else would
// be overkill.
long count = stream.count();
submonitor = SubMonitor.convert(monitor, (int) count);
Copy link
Contributor

Choose a reason for hiding this comment

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

The logic here is intricately tied to the if (Objects.equals(path.getParent(), root)) { guards in the walker. One might instead have specialized logic during preVisitDirectory for create a monitor only for the root.

In the end, this monitor will do a less good job of showing progress in a large branch. That makes me wonder if some kind of "stack" of monitors managed by preVisitDirectory/postVisitDirectory might not provide better progress? (Of course I'm not sure when/where such progress is displayed to the user, if anywhere.)

Copy link
Author

Choose a reason for hiding this comment

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

In the end, this monitor will do a less good job of showing progress in a large branch. That makes me wonder if some kind of "stack" of monitors managed by preVisitDirectory/postVisitDirectory might not provide better progress? (Of course I'm not sure when/where such progress is displayed to the user, if anywhere.)

I intentionally did id like this. I consider the progress monitoring here as very low priority. In my experience, the user does not care if 56% or 57% of the job is done. The progress bar is mostly used as an activity indicator that signals to the user that stuff is happening.
Using a stack of monitors would be more correct but also wrong since some directories are empty, other might by very big. In my opinion, it is a waist of time to optimize the progress monitoring.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, I don't disagree about the value of the monitor. It's just an observation.

That being said, I had to go hunting in the code to understand how this monitor count related to how it's actually used in the code.

@@ -0,0 +1,135 @@
/*******************************************************************************
* Copyright (c) 2025 Dieter Mai.
Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry I should have been more explicit. Please add the "and others" because you are also sharing the copyright with everyone. Everyone else has the copyright under the terms of the EPL-2.0 whereas you have the absolute copyright under your own terms (until someone contributes a changes and then EPL 2.0. applies to those changes).

Copy link
Author

Choose a reason for hiding this comment

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

Added "and others"

The previous implementation had the following flaws:

- On Linux, soft links to directories were followed, causing files
outside
the workspace to be deleted.
- On Windows, the read-only flag was not removed explicitly. Before Java
25, this was done implicitly by the File.delete() method. Since Java 25,
the flag must be removed before calling File.delete() or Files.delete().
See JDK-8355954.

This PR changes the implementation to:

- Use the NIO file walker to iterate the root directory.
- Avoid following symlinks.
- Remove the Windows read-only flag explicitly.

Signed-off-by: Dieter Mai <maidieter@googlemail.com>
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.

CoreUtility.deleteContent() deletes files outside of the workspace

2 participants