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 9100d103870..a85852e9594 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 @@ -1099,15 +1099,16 @@ public void updateLocalSync(ResourceInfo info, long localSyncInfo) { } /** - * The target must exist in the workspace. The content InputStream is - * closed even if the method fails. If the force flag is false we only write - * the file if it does not exist or if it is already local and the timestamp - * has NOT changed since last synchronization, otherwise a CoreException - * is thrown. + * The target must exist in the workspace and must remain existing while + * executing this method. The content InputStream is closed even if the method + * fails. If the force flag is false we only write the file if it does not exist + * or if it is already local and the timestamp has NOT changed since last + * synchronization, otherwise a CoreException is thrown. */ public void write(IFile target, InputStream content, IFileInfo fileInfo, int updateFlags, boolean append, IProgressMonitor monitor) throws CoreException { SubMonitor subMonitor = SubMonitor.convert(monitor, 4); try { + assertExists(target); IFileStore store = getStore(target); if (fileInfo.getAttribute(EFS.ATTRIBUTE_READ_ONLY)) { String message = NLS.bind(Messages.localstore_couldNotWriteReadOnly, target.getFullPath()); @@ -1122,10 +1123,8 @@ public void write(IFile target, InputStream content, IFileInfo fileInfo, int upd } } else { if (target.isLocal(IResource.DEPTH_ZERO)) { + assertExists(target); ResourceInfo info = ((Resource) target).getResourceInfo(true, false); - if (info == null) { - throw new IllegalStateException("No ResourceInfo for: " + target); //$NON-NLS-1$ - } // test if timestamp is the same since last synchronization if (lastModified != info.getLocalSyncInfo()) { asyncRefresh(target); @@ -1172,6 +1171,7 @@ public void write(IFile target, InputStream content, IFileInfo fileInfo, int upd subMonitor.split(1); } int options = append ? EFS.APPEND : EFS.NONE; + assertExists(target); OutputStream out = store.openOutputStream(options, subMonitor.split(1)); if (restoreHiddenAttribute) { fileInfo.setAttribute(EFS.ATTRIBUTE_HIDDEN, true); @@ -1182,11 +1182,8 @@ public void write(IFile target, InputStream content, IFileInfo fileInfo, int upd FileUtil.transferStreams(content, out, store.toString(), subMonitor.split(1)); // get the new last modified time and stash in the info lastModified = store.fetchInfo().getLastModified(); + assertExists(target); ResourceInfo info = ((Resource) target).getResourceInfo(false, true); - if (info == null) { - // happens see Bug 571133 - throw new IllegalStateException("No ResourceInfo for: " + target); //$NON-NLS-1$ - } updateLocalSync(info, lastModified); info.incrementContentId(); info.clear(M_CONTENT_CACHE); @@ -1196,6 +1193,13 @@ public void write(IFile target, InputStream content, IFileInfo fileInfo, int upd } } + private void assertExists(IFile target) { + if (!target.exists()) { + String message = NLS.bind(Messages.localstore_fileNotFound, target.getFullPath()); + throw new IllegalStateException(message); + } + } + /** * If force is false, this method fails if there is already a resource in * target's location. diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/localstore/FileSystemResourceManagerTest.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/localstore/FileSystemResourceManagerTest.java index 68afaa3f462..188f72dfeab 100644 --- a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/localstore/FileSystemResourceManagerTest.java +++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/localstore/FileSystemResourceManagerTest.java @@ -282,7 +282,8 @@ public void testWriteFile() throws CoreException { /* test the overwrite parameter (false) */ ensureDoesNotExistInFileSystem(file); // FIXME Race Condition with asynchronous workplace refresh see Bug 571133 InputStream another3 = getContents(anotherContent); - assertThrows("Should fail writing non existing file", CoreException.class, + waitForRefresh(); // wait for refresh to ensure that file is not present in workspace + assertThrows("Should fail writing non existing file", IllegalStateException.class, () -> write(file, another3, false, null)); /* remove trash */ @@ -290,7 +291,29 @@ public void testWriteFile() throws CoreException { } @Test - public void testWriteFile2() { + + public void testWriteFileConcurrentlyRemoved() throws CoreException { + /* initialize common objects */ + IProject project = projects[0]; + IFile file = project.getFile("testWriteFile"); + ensureExistsInWorkspace(file, true); + String content = "original"; + + /* write file for the first time */ + write(file, getContents(content), true, null); + + IProgressMonitor monitorRemovingFileOnWriteProgress = new NullProgressMonitor() { + @Override + public void worked(int work) { + ensureDoesNotExistInWorkspace(file); + } + }; + assertThrows("Should fail writing file that is concurrently removed", IllegalStateException.class, + () -> write(file, getContents(content), false, monitorRemovingFileOnWriteProgress)); + } + + @Test + public void testWriteFileNotInWorkspace() { // Bug 571133 IProject project = projects[0]; IFile file = project.getFile("testWriteFile2"); @@ -390,7 +413,7 @@ protected void write(final IFile file, final InputStream contents, final boolean try { IWorkspace workspace = getWorkspace(); assertNotNull("workspace cannot be null", workspace); - workspace.run(new WriteFileContents(file, contents, force, getLocalManager()), null); + workspace.run(new WriteFileContents(file, contents, force, getLocalManager()), monitor); } catch (Throwable t) { // Bug 541493: we see unlikely stack traces reported by JUnit here, log the // exceptions in case JUnit filters stack frames