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 6a011fa99a9..bcfaaeb9ae8 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.300.qualifier +Bundle-Version: 3.24.0.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/resources/File.java b/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/resources/File.java index 54a72e30207..eff57d98b85 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 @@ -41,6 +41,7 @@ import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceStatus; +import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; @@ -61,6 +62,12 @@ */ public class File extends Resource implements IFile { + /** + * Session property used to mark a file as containing restricted content + */ + private static final QualifiedName RESTRICTED_CONTENT = + new QualifiedName(ResourcesPlugin.PI_RESOURCES, "restrictedContent"); //$NON-NLS-1$ + protected File(IPath path, Workspace container) { super(path, container); } @@ -670,4 +677,14 @@ public String getLineSeparator(boolean checkParent) throws CoreException { return checkParent ? getProject().getDefaultLineSeparator() : null; } + @Override + public boolean isContentRestricted() throws CoreException { + Object sessionProperty = getSessionProperty(RESTRICTED_CONTENT); + return Boolean.TRUE.equals(sessionProperty); + } + + @Override + public void setContentRestricted(boolean restricted) throws CoreException { + setSessionProperty(RESTRICTED_CONTENT, restricted ? Boolean.TRUE : null); + } } 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 65864100f6b..c95fde8fd4f 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2015 IBM Corporation and others. + * Copyright (c) 2000, 2026 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -21,7 +21,9 @@ import java.io.Reader; import java.net.URI; import java.util.Objects; +import org.eclipse.core.internal.resources.ResourceException; import org.eclipse.core.internal.utils.FileUtil; +import org.eclipse.core.internal.utils.Messages; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IPath; @@ -32,6 +34,7 @@ import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.content.IContentDescription; import org.eclipse.core.runtime.content.IContentTypeManager; +import org.eclipse.osgi.util.NLS; /** * Files are leaf resources which contain data. @@ -1414,4 +1417,37 @@ public default String readString() throws CoreException { public default String getLineSeparator(boolean checkParent) throws CoreException { return getProject().getDefaultLineSeparator(); } + + /** + * Returns whether the current file is marked as containing restricted + * (sensitive) content, where some IDE functionality related to the file content + * might be limited. The file must exist. + * + * @return whether the current file is marked as containing sensitive content. + * This flag is not persisted and is {@code false} by default + * @throws CoreException if the file doesn't exist or if this method fails + * @since 3.24 + */ + default boolean isContentRestricted() throws CoreException { + if (!exists()) { + String message = NLS.bind(Messages.resources_mustExist, getFullPath()); + throw new ResourceException(IResourceStatus.RESOURCE_NOT_FOUND, getFullPath(), message, null); + } + return false; + } + + /** + * Marks the current file as containing restricted (sensitive) content. Some IDE + * functionality related to the file content might be limited as long as the + * file is marked as restricted. The file must exist. This flag is not persisted + * and is {@code false} by default. + * + * @param restricted true if the file should be marked restricted, + * false if the file should be unmarked + * @throws CoreException if the file doesn't exist or if this method fails + * @since 3.24 + */ + default void setContentRestricted(boolean restricted) throws CoreException { + throw new CoreException(Status.error("Not implemented")); //$NON-NLS-1$ + } } diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/resources/AllInternalResourcesTests.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/resources/AllInternalResourcesTests.java index 013b69e6e5b..fdfee9a0a0c 100644 --- a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/resources/AllInternalResourcesTests.java +++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/resources/AllInternalResourcesTests.java @@ -32,6 +32,7 @@ ResourceInfoTest.class, // WorkspaceConcurrencyTest.class, // WorkspacePreferencesTest.class, // + RestrictedFileTests.class, // }) public class AllInternalResourcesTests { } diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/resources/RestrictedFileTests.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/resources/RestrictedFileTests.java new file mode 100644 index 00000000000..ddb7fdb7003 --- /dev/null +++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/resources/RestrictedFileTests.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2026 Simeon Andreev and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Simeon Andreev - initial API and implementation + *******************************************************************************/ +package org.eclipse.core.tests.internal.resources; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.tests.resources.util.WorkspaceResetExtension; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +@ExtendWith(WorkspaceResetExtension.class) +public class RestrictedFileTests { + + @Test + public void testRestrictedFile() throws Exception { + IWorkspace workspace = ResourcesPlugin.getWorkspace(); + IWorkspaceRoot root = workspace.getRoot(); + IProject project = root.getProject(RestrictedFileTests.class.getSimpleName()); + try { + project.create(null); + project.open(null); + + IFile file1 = project.getFile("test1.txt"); + IFile file2 = project.getFile("test2.txt"); + + try { + file1.isContentRestricted(); + fail("Should not work on not existing files"); + } catch (CoreException e) { + // expected, file should not exist + } + + file1.create("line 1".getBytes(), IResource.FORCE, null); + file2.create("line 1".getBytes(), IResource.FORCE, null); + + assertFalse(file1.isContentRestricted(), "Expected file to not be restricted"); + assertFalse(file2.isContentRestricted(), "Expected file to not be restricted"); + + file1.setContentRestricted(true); + assertTrue(file1.isContentRestricted(), "Expected file to be restricted"); + assertFalse(file2.isContentRestricted(), "Expected file to not be restricted"); + + file1 = project.getFile("test1.txt"); + file2 = project.getFile("test2.txt"); + assertTrue(file1.isContentRestricted(), "Expected file to be restricted"); + assertFalse(file2.isContentRestricted(), "Expected file to not be restricted"); + } finally { + project.delete(true, null); + } + } +}