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 8a94d8ace4d..5cc21b19a76 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
@@ -1275,7 +1275,7 @@ private void prepareWrite(IFile target, IFileInfo fileInfo, int updateFlags, boo
throw new ResourceException(IResourceStatus.NOT_FOUND_LOCAL, target.getFullPath(), message, null);
}
} else {
- if (!BitMask.isSet(updateFlags, IResource.REPLACE) && fileInfo.exists()) {
+ if (fileInfo.exists()) {
String message = NLS.bind(Messages.localstore_resourceExists, target.getFullPath());
throw new ResourceException(IResourceStatus.EXISTS_LOCAL, target.getFullPath(), message, null);
}
diff --git a/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/File.java b/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/File.java
index c699cae990a..b5a2ed5cd22 100644
--- a/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/File.java
+++ b/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/File.java
@@ -126,7 +126,7 @@ public void create(InputStream content, int updateFlags, IProgressMonitor monito
final ISchedulingRule rule = workspace.getRuleFactory().createRule(this);
try {
workspace.prepareOperation(rule, subMonitor.newChild(1));
- checkCreatable(updateFlags);
+ checkCreatable();
workspace.beginOperation(true);
IFileStore store = getStore();
IFileInfo localInfo = create(updateFlags, subMonitor.newChild(40), store);
@@ -172,7 +172,7 @@ public void create(byte[] content, int updateFlags, IProgressMonitor monitor) th
final ISchedulingRule rule = workspace.getRuleFactory().createRule(this);
try {
workspace.prepareOperation(rule, subMonitor.newChild(1));
- checkCreatable(updateFlags);
+ checkCreatable();
workspace.beginOperation(true);
IFileStore store = getStore();
IFileInfo localInfo = create(updateFlags, subMonitor.newChild(40), store);
@@ -202,10 +202,8 @@ public void create(byte[] content, int updateFlags, IProgressMonitor monitor) th
}
}
- private void checkCreatable(int updateFlags) throws CoreException {
- if ((updateFlags & IResource.REPLACE) == 0) {
- checkDoesNotExist();
- }
+ private void checkCreatable() throws CoreException {
+ checkDoesNotExist();
Container parent = (Container) getParent();
ResourceInfo info = parent.getResourceInfo(false, false);
parent.checkAccessible(getFlags(info));
@@ -232,7 +230,7 @@ private IFileInfo create(int updateFlags, SubMonitor subMonitor, IFileStore stor
}
}
} else {
- if (!BitMask.isSet(updateFlags, IResource.REPLACE) && localInfo.exists()) {
+ if (localInfo.exists()) {
// return an appropriate error message for case variant collisions
if (!Workspace.caseSensitive) {
String name = getLocalManager().getLocalName(store);
@@ -433,6 +431,10 @@ public void setContents(InputStream content, int updateFlags, IProgressMonitor m
checkAccessible(getFlags(info));
workspace.beginOperation(true);
IFileInfo fileInfo = getStore().fetchInfo();
+ if (BitMask.isSet(updateFlags, IResource.DERIVED)) {
+ // update of derived flag during IFile.write:
+ info.set(ICoreConstants.M_DERIVED);
+ }
internalSetContents(content, fileInfo, updateFlags, false, subMonitor.newChild(99));
} catch (OperationCanceledException e) {
workspace.getWorkManager().operationCanceled();
@@ -461,6 +463,10 @@ public void setContents(byte[] content, int updateFlags, IProgressMonitor monito
checkAccessible(getFlags(info));
workspace.beginOperation(true);
IFileInfo fileInfo = getStore().fetchInfo();
+ if (BitMask.isSet(updateFlags, IResource.DERIVED)) {
+ // update of derived flag during IFile.write:
+ info.set(ICoreConstants.M_DERIVED);
+ }
internalSetContents(content, fileInfo, updateFlags, false, subMonitor.newChild(99));
} catch (OperationCanceledException e) {
workspace.getWorkManager().operationCanceled();
diff --git a/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/IFile.java b/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/IFile.java
index dda165e24b6..2f8338c43eb 100644
--- a/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/IFile.java
+++ b/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/resources/IFile.java
@@ -304,13 +304,6 @@ public interface IFile extends IResource, IEncodedStorage, IAdaptable {
* with a value of true
immediately after creating the resource.
*
- * The {@link IResource#KEEP_HISTORY} update flag indicates that the history of this file is kept if any - *
- *- * The {@link IResource#REPLACE} update flag indicates that this resource is overridden if already existing. - * - *
- *
* The {@link IResource#TEAM_PRIVATE} update flag indicates that this resource
* should immediately be set as a team private resource. Specifying this flag
* is equivalent to atomically calling {@link IResource#setTeamPrivateMember(boolean)}
@@ -338,9 +331,7 @@ public interface IFile extends IResource, IEncodedStorage, IAdaptable {
* @param source an input stream containing the initial contents of the file,
* or null
if the file should be marked as not local
* @param updateFlags bit-wise or of update flag constants
- * ({@link IResource#FORCE}, {@link IResource#DERIVED},
- * {@link IResource#KEEP_HISTORY}, {@link IResource#REPLACE},
- * and {@link IResource#TEAM_PRIVATE})
+ * ({@link IResource#FORCE}, {@link IResource#DERIVED}, and {@link IResource#TEAM_PRIVATE})
* @param monitor a progress monitor, or null
if progress
* reporting is not desired
* @exception CoreException if this method fails. Reasons include:
@@ -400,9 +391,7 @@ public default void create(byte[] content, boolean force, boolean derived, IProg
*
* @param content the content as byte array
* @param createFlags bit-wise or of flag constants ({@link IResource#FORCE},
- * {@link IResource#DERIVED},
- * {@link IResource#KEEP_HISTORY},
- * {@link IResource#REPLACE}, and
+ * {@link IResource#DERIVED}, and
* {@link IResource#TEAM_PRIVATE})
* @param monitor a progress monitor, or null
if progress
* reporting is not desired
@@ -416,17 +405,19 @@ public default void create(byte[] content, int createFlags, IProgressMonitor mon
/**
* Creates the file and sets the file content. If the file already exists in
* workspace its content is replaced. Shortcut for calling
- * {@link #create(byte[], int, IProgressMonitor)} with flags depending on the
- * boolean parameters given and {@link IResource#REPLACE}.
+ * {@link #setContents(byte[], boolean, boolean, IProgressMonitor)} or
+ * {@link #create(byte[], boolean, boolean, IProgressMonitor)} if the file does
+ * not {@link #exists()}.
*
* @param content the new content bytes. Must not be null.
* @param force a flag controlling how to deal with resources that are not
* in sync with the local file system
* @param derived Specifying this flag is equivalent to atomically calling
* {@link IResource#setDerived(boolean)} immediately after
- * creating the resource or non-atomically setting the
- * derived flag before setting the content of an already
- * existing file
+ * creating the resource or atomically setting the derived
+ * flag before setting the content of an already existing
+ * file if derived==true. A value of false will not update
+ * the derived flag of an existing file.
* @param keepHistory a flag indicating whether or not store the current
* contents in the local history if the file did already
* exist
@@ -438,8 +429,14 @@ public default void create(byte[] content, int createFlags, IProgressMonitor mon
public default void write(byte[] content, boolean force, boolean derived, boolean keepHistory,
IProgressMonitor monitor) throws CoreException {
Objects.requireNonNull(content);
- create(content, (force ? IResource.FORCE : 0) | (derived ? IResource.DERIVED : 0)
- | (keepHistory ? IResource.KEEP_HISTORY : 0) | IResource.REPLACE, monitor);
+ if (exists()) {
+ int updateFlags = (derived ? IResource.DERIVED : IResource.NONE)
+ | (force ? IResource.FORCE : IResource.NONE)
+ | (keepHistory ? IResource.KEEP_HISTORY : IResource.NONE);
+ setContents(content, updateFlags, monitor);
+ } else {
+ create(content, force, derived, monitor);
+ }
}
/**
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 fbb0e53ca69..91ea4c35313 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
@@ -44,6 +44,7 @@
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFileState;
@@ -53,7 +54,9 @@
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceStatus;
+import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceDescription;
+import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
@@ -497,23 +500,60 @@ public void testWrite() throws CoreException {
boolean setDerived = i % 2 == 0;
boolean deleteBefore = (i >> 1) % 2 == 0;
boolean keepHistory = (i >> 2) % 2 == 0;
+ boolean oldDerived1 = false;
if (deleteBefore) {
derived.delete(false, null);
+ } else {
+ oldDerived1 = derived.isDerived();
}
assertEquals(!deleteBefore, derived.exists());
FussyProgressMonitor monitor = new FussyProgressMonitor();
+ AtomicInteger changeCount = new AtomicInteger();
+ ResourcesPlugin.getWorkspace().addResourceChangeListener(event -> changeCount.incrementAndGet());
derived.write(("updateOrCreate" + i).getBytes(), false, setDerived, keepHistory, monitor);
+ assertEquals("not atomic", 1, changeCount.get());
monitor.assertUsedUp();
- assertEquals(setDerived, derived.isDerived());
+ if (deleteBefore) {
+ assertEquals(setDerived, derived.isDerived());
+ } else {
+ assertEquals(oldDerived1 || setDerived, derived.isDerived());
+ }
assertFalse(derived.isTeamPrivateMember());
assertTrue(derived.exists());
IFileState[] history1 = derived.getHistory(null);
+ changeCount.set(0);
derived.write(("update" + i).getBytes(), false, false, keepHistory, null);
+ boolean oldDerived2 = derived.isDerived();
+ assertEquals(oldDerived2, derived.isDerived());
+ assertEquals("not atomic", 1, changeCount.get());
IFileState[] history2 = derived.getHistory(null);
- assertEquals(keepHistory ? 1 : 0, history2.length - history1.length);
+ assertEquals((keepHistory && !oldDerived2) ? 1 : 0, history2.length - history1.length);
}
}
+
+ @Test
+ public void testWriteRule() throws CoreException {
+ IFile resource = projects[0].getFile("derived.txt");
+ createInWorkspace(projects[0]);
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ resource.delete(false, null);
+ AtomicInteger changeCount = new AtomicInteger();
+ ResourcesPlugin.getWorkspace().addResourceChangeListener(event -> changeCount.incrementAndGet());
+ workspace.run(pm -> {
+ resource.write(("create").getBytes(), false, false, false, null);
+ }, workspace.getRuleFactory().createRule(resource), IWorkspace.AVOID_UPDATE, null);
+ assertTrue(resource.exists());
+ assertEquals("not atomic", 1, changeCount.get());
+ // test that modifyRule can be used for IFile.write() if the file already exits:
+ changeCount.set(0);
+ workspace.run(pm -> {
+ resource.write(("replace").getBytes(), false, false, false, null);
+ }, workspace.getRuleFactory().modifyRule(resource), IWorkspace.AVOID_UPDATE, null);
+ assertTrue(resource.exists());
+ assertEquals("not atomic", 1, changeCount.get());
+ }
+
@Test
public void testDeltaOnCreateDerived() throws CoreException {
IFile derived = projects[0].getFile("derived.txt");