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 5cc21b19a76..ce9de460bbd 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 @@ -1211,7 +1211,7 @@ public void write(IFile target, InputStream content, IFileInfo fileInfo, int upd try (content) { Resource targetResource = (Resource) target; IFileStore store = getStore(target); - prepareWrite(target, fileInfo, updateFlags, append, targetResource, store); + prepareWrite(target, fileInfo, updateFlags, append, targetResource, store, false); // On Windows an attempt to open an output stream on a hidden file results in FileNotFoundException. // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=194216 @@ -1243,7 +1243,7 @@ public void write(IFile target, InputStream content, IFileInfo fileInfo, int upd } private void prepareWrite(IFile target, IFileInfo fileInfo, int updateFlags, boolean append, - Resource targetResource, IFileStore store) throws CoreException { + Resource targetResource, IFileStore store, boolean optimistic) throws CoreException { if (fileInfo.getAttribute(EFS.ATTRIBUTE_READ_ONLY)) { String message = NLS.bind(Messages.localstore_couldNotWriteReadOnly, target.getFullPath()); throw new ResourceException(IResourceStatus.FAILED_WRITE_LOCAL, target.getFullPath(), message, null); @@ -1292,11 +1292,14 @@ private void prepareWrite(IFile target, IFileInfo fileInfo, int updateFlags, boo // never move to the history store, because then the file is missing if write // fails getHistoryStore().addState(target.getFullPath(), store, fileInfo, false); - if (!fileInfo.exists()) { - IFileStore parent = store.getParent(); - IFileInfo parentInfo = parent.fetchInfo(); - if (!parentInfo.exists()) { - parent.mkdir(EFS.NONE, null); + // let's be optimistic that the parent directory exists? + if (!optimistic) { + if (!fileInfo.exists()) { + IFileStore parent = store.getParent(); + IFileInfo parentInfo = parent.fetchInfo(); + if (!parentInfo.exists()) { + parent.mkdir(EFS.NONE, null); + } } } } @@ -1327,7 +1330,7 @@ public void write(IFile target, byte[] content, IFileInfo fileInfo, int updateFl SubMonitor subMonitor = SubMonitor.convert(monitor, 4); Resource targetResource = (Resource) target; IFileStore store = getStore(target); - prepareWrite(target, fileInfo, updateFlags, append, targetResource, store); + prepareWrite(target, fileInfo, updateFlags, append, targetResource, store, true); // On Windows an attempt to open an output stream on a hidden file results in // FileNotFoundException. @@ -1342,7 +1345,23 @@ public void write(IFile target, byte[] content, IFileInfo fileInfo, int updateFl subMonitor.split(1); } int options = append ? EFS.APPEND : EFS.NONE; - store.write(content, options, subMonitor.split(1)); + try { + store.write(content, options, subMonitor.split(1)); + } catch (CoreException e) { + if (append) { + throw e; + } + if (e.getStatus().getCode() != EFS.ERROR_WRITE) { + throw e; + } + IFileStore parent = store.getParent(); + IFileInfo parentInfo = parent.fetchInfo(); + if (!parentInfo.exists()) { + parent.mkdir(EFS.NONE, null); + // try again + store.write(content, options, null); + } + } if (restoreHiddenAttribute) { fileInfo.setAttribute(EFS.ATTRIBUTE_HIDDEN, true); store.putInfo(fileInfo, EFS.SET_ATTRIBUTES, subMonitor.split(1)); diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/IFileTest.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/IFileTest.java index f1738069852..8f38739d98a 100644 --- a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/IFileTest.java +++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/IFileTest.java @@ -46,6 +46,7 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; +import org.eclipse.core.internal.resources.ResourceException; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFileState; @@ -507,6 +508,27 @@ public void testCreateBytes() throws CoreException { assertFalse(derived.isDerived()); assertFalse(derived.isTeamPrivateMember()); assertEquals("notDerived", derived.readString()); + + IFolder subFolder = projects[0].getFolder("subFolder"); + subFolder.create(true, true, null); + subFolder.getRawLocation().toFile().delete(); + + IFile orphan = subFolder.getFile("myParentDoesNotExist.txt"); + monitor.prepare(); + orphan.write("parentDoesNotExistInFileSystemButInWorkspace".getBytes(), true, false, false, monitor); + monitor.assertUsedUp(); + assertEquals("parentDoesNotExistInFileSystemButInWorkspace", orphan.readString()); + + monitor.prepare(); + orphan.getParent().delete(true, null); + // if the parent is deleted in workspace Exception is expected: + try { + orphan.write("parentDoesNotExist - not even in workspace".getBytes(), true, false, false, monitor); + assertFalse("should not be reached", true); + } catch (ResourceException expected) { + monitor.assertUsedUp(); + assertFalse(orphan.exists()); + } } @Test