diff --git a/resources/bundles/org.eclipse.core.resources/META-INF/MANIFEST.MF b/resources/bundles/org.eclipse.core.resources/META-INF/MANIFEST.MF
index 82730f06304..f089e0fbcc0 100644
--- a/resources/bundles/org.eclipse.core.resources/META-INF/MANIFEST.MF
+++ b/resources/bundles/org.eclipse.core.resources/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.core.resources; singleton:=true
-Bundle-Version: 3.23.100.qualifier
+Bundle-Version: 3.23.200.qualifier
Bundle-Activator: org.eclipse.core.resources.ResourcesPlugin
Bundle-Vendor: %providerName
Bundle-Localization: plugin
diff --git a/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/FileSystemResourceManager.java b/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/FileSystemResourceManager.java
index f1b404cf443..2a83f0d2071 100644
--- a/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/FileSystemResourceManager.java
+++ b/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/FileSystemResourceManager.java
@@ -935,6 +935,10 @@ private IFileStore getFileStore(IFile target, boolean force) throws ResourceExce
final IFileInfo fileInfo = store.fetchInfo();
Resource resource = (Resource) target;
ResourceInfo info = resource.getResourceInfo(true, false);
+ if (info == null) {
+ String message = NLS.bind(Messages.resources_mustExist, target.getFullPath());
+ throw new ResourceException(IResourceStatus.RESOURCE_NOT_FOUND, target.getFullPath(), message, null);
+ }
if (fileInfo.getLastModified() != info.getLocalSyncInfo()) {
asyncRefresh(target);
String message = NLS.bind(Messages.localstore_resourceIsOutOfSync, target.getFullPath());
diff --git a/resources/tests/org.eclipse.core.tests.resources/META-INF/MANIFEST.MF b/resources/tests/org.eclipse.core.tests.resources/META-INF/MANIFEST.MF
index 0af9e7d8aa7..ca13fe16300 100644
--- a/resources/tests/org.eclipse.core.tests.resources/META-INF/MANIFEST.MF
+++ b/resources/tests/org.eclipse.core.tests.resources/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Eclipse Core Tests Resources
Bundle-SymbolicName: org.eclipse.core.tests.resources; singleton:=true
-Bundle-Version: 3.11.1100.qualifier
+Bundle-Version: 3.11.1200.qualifier
Bundle-Vendor: Eclipse.org
Export-Package: org.eclipse.core.tests.filesystem,
org.eclipse.core.tests.internal.alias,
diff --git a/resources/tests/org.eclipse.core.tests.resources/pom.xml b/resources/tests/org.eclipse.core.tests.resources/pom.xml
index 8ae4d950aee..8e86a6785a7 100644
--- a/resources/tests/org.eclipse.core.tests.resources/pom.xml
+++ b/resources/tests/org.eclipse.core.tests.resources/pom.xml
@@ -18,7 +18,7 @@
4.39.0-SNAPSHOT
org.eclipse.core.tests.resources
- 3.11.1100-SNAPSHOT
+ 3.11.1200-SNAPSHOT
eclipse-test-plugin
diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/regression/IFileTest.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/regression/IFileTest.java
index 0c333a57054..b9be0e93c3c 100644
--- a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/regression/IFileTest.java
+++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/regression/IFileTest.java
@@ -13,6 +13,7 @@
*******************************************************************************/
package org.eclipse.core.tests.resources.regression;
+import static java.lang.System.currentTimeMillis;
import static org.assertj.core.api.Assertions.assertThat;
import static org.eclipse.core.resources.ResourcesPlugin.getWorkspace;
import static org.eclipse.core.tests.resources.ResourceTestUtil.createInWorkspace;
@@ -24,6 +25,9 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
@@ -31,7 +35,10 @@
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceStatus;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform.OS;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.tests.resources.util.WorkspaceResetExtension;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -125,4 +132,82 @@ public void testBug43936() throws CoreException {
project.setDescription(desc, createTestMonitor());
}
+ /**
+ * Do not throw RuntimeException when accessing a deleted file
+ */
+ @Test
+ public void testIssue2290() throws CoreException, InterruptedException {
+ IProject project = getWorkspace().getRoot().getProject("MyProject");
+ IFile subject = project.getFile("subject.txt");
+ Job createDelete = Job.create("Create/delete", monitor -> {
+ try {
+ while (!monitor.isCanceled()) {
+ createInWorkspace(subject);
+ while (!monitor.isCanceled()) {
+ try {
+ subject.delete(true, monitor);
+ break;
+ } catch (CoreException e) {
+ // On Windows, files opened for reading can't be deleted, try again
+ if (e.getStatus().getCode() != IResourceStatus.FAILED_DELETE_LOCAL) {
+ throw e;
+ }
+ }
+ }
+ }
+ } catch (CoreException e) {
+ return e.getStatus();
+ }
+ return Status.OK_STATUS;
+ });
+ createDelete.setPriority(Job.INTERACTIVE);
+
+ long stop = currentTimeMillis() + 1000;
+ try {
+ createDelete.schedule();
+ while (currentTimeMillis() < stop) {
+ assertContentAccessibleOrNotFound(subject); // should not throw
+ }
+ } finally {
+ createDelete.cancel();
+ createDelete.join();
+ IStatus result = createDelete.getResult();
+ if (!result.isOK()) {
+ throw new CoreException(result);
+ }
+ }
+ }
+
+ private void assertContentAccessibleOrNotFound(IFile file) {
+ try (InputStream contents = file.getContents(false)) {
+ contents.transferTo(OutputStream.nullOutputStream());
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ } catch (CoreException e) {
+ switch (e.getStatus().getCode()) {
+ case IResourceStatus.RESOURCE_NOT_LOCAL:
+ case IResourceStatus.RESOURCE_NOT_FOUND:
+ case IResourceStatus.FAILED_READ_LOCAL:
+ case IResourceStatus.OUT_OF_SYNC_LOCAL:
+ break;
+ default:
+ throw new AssertionError(e);
+ }
+ }
+ try (InputStream contents = file.getContents(true)) {
+ contents.transferTo(OutputStream.nullOutputStream());
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ } catch (CoreException e) {
+ switch (e.getStatus().getCode()) {
+ case IResourceStatus.RESOURCE_NOT_LOCAL:
+ case IResourceStatus.RESOURCE_NOT_FOUND:
+ case IResourceStatus.FAILED_READ_LOCAL:
+ break;
+ default:
+ throw new AssertionError(e);
+ }
+ }
+ }
+
}