diff --git a/resources/bundles/org.eclipse.core.filesystem/META-INF/MANIFEST.MF b/resources/bundles/org.eclipse.core.filesystem/META-INF/MANIFEST.MF
index c317ba0769e..f62a84662c2 100644
--- a/resources/bundles/org.eclipse.core.filesystem/META-INF/MANIFEST.MF
+++ b/resources/bundles/org.eclipse.core.filesystem/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.core.filesystem; singleton:=true
-Bundle-Version: 1.10.400.qualifier
+Bundle-Version: 1.11.0.qualifier
Bundle-Localization: plugin
Require-Bundle: org.eclipse.equinox.common;bundle-version="[3.18.0,4.0.0)",
org.eclipse.equinox.registry;bundle-version="[3.2.0,4.0.0)",
diff --git a/resources/bundles/org.eclipse.core.filesystem/plugin.xml b/resources/bundles/org.eclipse.core.filesystem/plugin.xml
index a91ee65ed6d..de665c388f7 100644
--- a/resources/bundles/org.eclipse.core.filesystem/plugin.xml
+++ b/resources/bundles/org.eclipse.core.filesystem/plugin.xml
@@ -16,4 +16,11 @@
+
+
+
+
+
diff --git a/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/filesystem/ZipFileUtil.java b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/filesystem/ZipFileUtil.java
new file mode 100644
index 00000000000..6cb045a6aac
--- /dev/null
+++ b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/filesystem/ZipFileUtil.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Vector Informatik GmbH 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: Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.core.filesystem;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.HashSet;
+import java.util.Set;
+import org.eclipse.core.internal.filesystem.zip.ZipFileStore;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * Utility class to determine if a file is an archive based on file header information.
+ * This class checks for known file signatures to identify if a given file is a ZIP archive
+ * or a format based on ZIP, such as EPUB, JAR, ODF, and OOXML.
+ *
+ * @since 1.11
+ */
+public class ZipFileUtil {
+
+ private static final Set ARCHIVE_FILE_SIGNATURES = new HashSet<>();
+
+ static {
+ // Initializes known archive file signatures from Wikipedia's list of file signatures
+ // (https://en.wikipedia.org/wiki/List_of_file_signatures)
+ ARCHIVE_FILE_SIGNATURES.add(0x504B0304); // Standard ZIP file
+ ARCHIVE_FILE_SIGNATURES.add(0x504B0506); // Empty archive
+ ARCHIVE_FILE_SIGNATURES.add(0x504B0708); // Spanned archive
+ }
+
+ /**
+ * Determines if the given {@link IFileStore} represents an open ZIP file.
+ * This can be used to check if operations on a ZIP file should be allowed or handled differently.
+ *
+ * @param store The file store to check.
+ * @return true if the store is an instance of {@link ZipFileStore}, false otherwise.
+ */
+ public static boolean isInsideOpenZipFile(IFileStore store) {
+ return store instanceof ZipFileStore;
+ }
+
+ public static boolean isInsideOpenZipFile(URI locationURI) {
+ IFileStore store;
+ try {
+ store = EFS.getStore(locationURI);
+ } catch (CoreException e) {
+ return false;
+ }
+ return isInsideOpenZipFile(store);
+ }
+
+ //TODO Implement this method
+ public static boolean isOpenZipFile(IFileStore store) {
+ if (isInsideOpenZipFile(store)) {
+ ZipFileStore zipStore = (ZipFileStore) store;
+ return zipStore.getPath().isEmpty(); //if path is empty its the root
+ }
+ return false;
+ }
+
+ public static boolean isOpenZipFile(URI locationURI) {
+ IFileStore store;
+ try {
+ store = EFS.getStore(locationURI);
+ } catch (CoreException e) {
+ return false;
+ }
+ return isOpenZipFile(store);
+ }
+
+ public static boolean isNested(URI fileURI) {
+ if (fileURI.getScheme().contains("zip")) { //$NON-NLS-1$
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Checks if the provided {@link InputStream} represents a ZIP archive
+ * by reading its first four bytes and comparing them against known ZIP file signatures.
+ * This method throws {@link IOException} if the file signature does not match any known ZIP archive signatures.
+ *
+ * @param fis The {@link InputStream} of the file to check.
+ * @throws IOException If the file signature does not match known ZIP archive signatures
+ * or an I/O error occurs during reading from the stream.
+ */
+ public static void checkFileForZipHeader(InputStream fis) throws IOException {
+ byte[] bytes = new byte[4];
+ if (fis.read(bytes) == bytes.length) {
+ ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
+ int header = buffer.getInt();
+
+ if (!ARCHIVE_FILE_SIGNATURES.contains(header)) {
+ throw new IOException("Invalid archive file signature."); // Throws IOException if header is not recognized //$NON-NLS-1$
+ }
+ } else {
+ // Handle the case where not enough bytes are read
+ throw new IOException("Could not read enough data to check ZIP file header."); //$NON-NLS-1$
+ }
+ }
+}
diff --git a/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/zip/ZipFileStore.java b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/zip/ZipFileStore.java
new file mode 100644
index 00000000000..78c0696019e
--- /dev/null
+++ b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/zip/ZipFileStore.java
@@ -0,0 +1,559 @@
+/*******************************************************************************
+ * Copyright (c) 2022 IBM Corporation 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: IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.core.internal.filesystem.zip;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystemAlreadyExistsException;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitOption;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.StandardOpenOption;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.FileTime;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import org.eclipse.core.filesystem.EFS;
+import org.eclipse.core.filesystem.IFileInfo;
+import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.filesystem.provider.FileInfo;
+import org.eclipse.core.filesystem.provider.FileStore;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.osgi.framework.FrameworkUtil;
+
+/**
+ * File store implementation representing a file or directory inside a zip file.
+ * @since 1.11
+ */
+public class ZipFileStore extends FileStore {
+ /**
+ * The path of this store within the zip file.
+ */
+ private final IPath path;
+
+ /**
+ * The file store that represents the actual zip file.
+ */
+ private final IFileStore rootStore;
+
+ /**
+ * Creates a new zip file store.
+ */
+ public ZipFileStore(IFileStore rootStore, IPath path) {
+ this.rootStore = rootStore;
+ this.path = path.makeRelative();
+ }
+
+ private ZipEntry[] childEntries(IProgressMonitor monitor) throws CoreException {
+ List entryList = new ArrayList<>();
+ String myName = path.toString();
+
+ try (FileSystem zipFs = openZipFileSystem()) {
+ Path zipRoot = zipFs.getPath(myName);
+ Files.walkFileTree(zipRoot, EnumSet.noneOf(FileVisitOption.class), 1, new SimpleFileVisitor() {
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+ String entryName = zipRoot.relativize(file).toString();
+ if (!Files.isDirectory(file)) {
+ // For files, read attributes and create ZipEntry
+ ZipEntry zipEntry = new ZipEntry(entryName);
+ zipEntry.setSize(attrs.size());
+ zipEntry.setTime(attrs.lastModifiedTime().toMillis());
+ // Compressed size is not directly available; method is set based on ZIP standard
+ zipEntry.setMethod(ZipEntry.DEFLATED);
+ entryList.add(zipEntry);
+ } else {
+ // For directories, simply add them with a trailing slash
+ entryList.add(new ZipEntry(entryName + "/")); //$NON-NLS-1$
+ }
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
+ // Include directories only if they are not the root directory
+ if (!dir.equals(zipRoot)) {
+ String dirName = zipRoot.relativize(dir).toString() + "/"; //$NON-NLS-1$
+ entryList.add(new ZipEntry(dirName));
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ } catch (IOException | URISyntaxException e) {
+ throw new CoreException(new Status(IStatus.ERROR, getPluginId(), "Error reading ZIP file", e)); //$NON-NLS-1$
+ }
+
+ return entryList.toArray(new ZipEntry[0]);
+ }
+
+ @Override
+ public IFileInfo[] childInfos(int options, IProgressMonitor monitor) throws CoreException {
+ ZipEntry[] entries = childEntries(monitor);
+ int entryCount = entries.length;
+ IFileInfo[] infos = new IFileInfo[entryCount];
+ for (int i = 0; i < entryCount; i++) {
+ infos[i] = convertZipEntryToFileInfo(entries[i]);
+ }
+ return infos;
+ }
+
+ @Override
+ public String[] childNames(int options, IProgressMonitor monitor) throws CoreException {
+ ZipEntry[] entries = childEntries(monitor);
+ int entryCount = entries.length;
+ String[] names = new String[entryCount];
+ for (int i = 0; i < entryCount; i++) {
+ names[i] = computeName(entries[i]);
+ }
+ return names;
+ }
+
+ /**
+ * Computes the simple file name for a given zip entry.
+ */
+ private String computeName(ZipEntry entry) {
+ String name = entry.getName();
+ // removes "/" at the end
+ if (name.endsWith("/")) { //$NON-NLS-1$
+ name = name.substring(0, name.length() - 1);
+ }
+ // creates last segment after last /
+ int lastIndex = name.lastIndexOf('/');
+
+ if (lastIndex != -1) {
+ return name.substring(lastIndex + 1);
+ }
+
+ return name; // Falls kein '/' gefunden wurde
+ }
+
+ private IFileInfo convertToIFileInfo(Path zipEntryPath, BasicFileAttributes attrs) {
+ Path namePath = zipEntryPath.getFileName();
+ String name = namePath != null ? namePath.toString() : ""; //$NON-NLS-1$
+ FileInfo info = new FileInfo(name);
+ info.setExists(true);
+ info.setDirectory(attrs.isDirectory());
+ info.setLastModified(attrs.lastModifiedTime().toMillis());
+ info.setLength(attrs.size());
+ return info;
+ }
+
+ /**
+ * Creates a file info object corresponding to a given zip entry
+ *
+ * @param entry the zip entry
+ * @return The file info for a zip entry
+ */
+ private IFileInfo convertZipEntryToFileInfo(ZipEntry entry) {
+ FileInfo info = new FileInfo(computeName(entry));
+ if (entry.isDirectory()) {
+ info.setLastModified(EFS.NONE);
+ } else {
+ info.setLastModified(entry.getTime());
+ }
+
+ info.setExists(true);
+ info.setDirectory(entry.isDirectory());
+ info.setLength(entry.getSize());
+ return info;
+ }
+
+ @Override
+ protected void copyDirectory(IFileInfo sourceInfo, IFileStore destination, int options, IProgressMonitor monitor) throws CoreException {
+ if (!(destination instanceof ZipFileStore)) {
+ super.copyDirectory(sourceInfo, destination, options, monitor);
+ return;
+ }
+
+ if (!sourceInfo.isDirectory()) {
+ throw new CoreException(new Status(IStatus.ERROR, getPluginId(), "Source is not a directory")); //$NON-NLS-1$
+ }
+
+ try (FileSystem zipFs = openZipFileSystem()) {
+ Path sourceDir = zipFs.getPath(this.path.toString());
+ FileSystem destFs = ((ZipFileStore) destination).openZipFileSystem();
+ Path destDir = destFs.getPath(((ZipFileStore) destination).path.toString());
+
+ // Use Files.walk to iterate over each entry in the directory
+ Files.walk(sourceDir).forEach(sourcePath -> {
+ try {
+ Path destPath = destDir.resolve(sourceDir.relativize(sourcePath));
+ if (Files.isDirectory(sourcePath)) {
+ Files.createDirectories(destPath);
+ } else {
+ Files.copy(sourcePath, destPath, StandardCopyOption.REPLACE_EXISTING);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("Error copying directory contents", e); //$NON-NLS-1$
+ }
+ });
+ } catch (IOException | URISyntaxException e) {
+ throw new CoreException(new Status(IStatus.ERROR, getPluginId(), "Error copying directory within ZIP", e)); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ protected void copyFile(IFileInfo sourceInfo, IFileStore destination, int options, IProgressMonitor monitor) throws CoreException {
+ if (!(destination instanceof ZipFileStore)) {
+ super.copyFile(sourceInfo, destination, options, monitor);
+ return;
+ }
+
+ if (sourceInfo.isDirectory()) {
+ throw new CoreException(new Status(IStatus.ERROR, getPluginId(), "Source is a directory, not a file")); //$NON-NLS-1$
+ }
+
+ try (FileSystem zipFs = openZipFileSystem()) {
+ Path sourcePath = zipFs.getPath(this.path.toString());
+ FileSystem destFs = ((ZipFileStore) destination).openZipFileSystem();
+ Path destPath = destFs.getPath(((ZipFileStore) destination).path.toString());
+
+ // Copy the file with REPLACE_EXISTING option to overwrite if it already exists
+ Files.copy(sourcePath, destPath, StandardCopyOption.REPLACE_EXISTING);
+ } catch (IOException | URISyntaxException e) {
+ throw new CoreException(new Status(IStatus.ERROR, getPluginId(), "Error copying file within ZIP", e)); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public void delete(int options, IProgressMonitor monitor) throws CoreException {
+ Path toDelete = null;
+ try (FileSystem zipFs = openZipFileSystem()) {
+ toDelete = zipFs.getPath(path.toString());
+ if (Files.exists(toDelete)) {
+ deleteRecursive(toDelete);
+ }
+ } catch (IOException | URISyntaxException e) {
+ throw new CoreException(new Status(IStatus.ERROR, "org.eclipse.core.filesystem.zip", "Error deleting file from zip: " + toDelete, e)); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ private void deleteRecursive(Path pathToDelete) throws IOException {
+ if (Files.isDirectory(pathToDelete)) {
+ // Use try-with-resources to close the directory stream automatically
+ try (Stream entries = Files.walk(pathToDelete)) {
+ // We need to sort it in reverse order so directories come after their contents
+ List sortedPaths = entries.sorted(Comparator.reverseOrder()).collect(Collectors.toList());
+ for (Path entry : sortedPaths) {
+ Files.delete(entry);
+ }
+ }
+ } else {
+ Files.delete(pathToDelete);
+ }
+ }
+
+ @Override
+ public IFileInfo fetchInfo(int options, IProgressMonitor monitor) throws CoreException {
+ try (FileSystem zipFs = openZipFileSystem()) {
+ Path zipEntryPath = zipFs.getPath(path.toString());
+ if (Files.exists(zipEntryPath)) {
+ BasicFileAttributes attrs = Files.readAttributes(zipEntryPath, BasicFileAttributes.class);
+ return convertToIFileInfo(zipEntryPath, attrs);
+ }
+ } catch (IOException | URISyntaxException e) {
+ throw new CoreException(new Status(IStatus.ERROR, getPluginId(), "Error accessing ZIP file", e)); //$NON-NLS-1$
+ }
+
+ // Correctly set up FileInfo before returning
+ FileInfo notFoundInfo = new FileInfo(path.lastSegment());
+ notFoundInfo.setExists(false);
+ return notFoundInfo;
+ }
+
+ /**
+ * Finds the zip entry with the given name in this zip file. Returns the
+ * entry and leaves the input stream open positioned at the beginning of the
+ * bytes of that entry. Returns null if the entry could not be found.
+ */
+ private ZipEntry findEntry(String name, ZipInputStream in) throws IOException {
+ ZipEntry current;
+ while ((current = in.getNextEntry()) != null) {
+ if (current.getName().equals(name)) {
+ return current;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public IFileStore getChild(String name) {
+ return new ZipFileStore(rootStore, path.append(name));
+ }
+
+ @Override
+ public String getName() {
+ String name = path.lastSegment();
+ return name == null ? "" : name; //$NON-NLS-1$
+ }
+
+ @Override
+ public IFileStore getParent() {
+ if (path.segmentCount() > 0) {
+ return new ZipFileStore(rootStore, path.removeLastSegments(1));
+ }
+ // the root entry has no parent
+ return null;
+ }
+
+ private String getPluginId() {
+ return FrameworkUtil.getBundle(this.getClass()).getSymbolicName();
+ }
+
+ public IPath getPath() {
+ return path;
+ }
+
+ private boolean isNested() {
+ return this.rootStore instanceof ZipFileStore;
+ }
+
+ @Override
+ public IFileStore mkdir(int options, IProgressMonitor monitor) throws CoreException {
+ URI zipUri;
+ try {
+ zipUri = new URI("jar:" + rootStore.toURI().toString() + "!/"); //$NON-NLS-1$ //$NON-NLS-2$
+ } catch (URISyntaxException e) {
+ throw new CoreException(new Status(IStatus.ERROR, "org.eclipse.core.filesystem.zip", "Invalid ZIP file URI", e)); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ Map env = new HashMap<>();
+ env.put("create", "false"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ // Assuming the directory to create is represented by 'this.path'
+ try (FileSystem zipFs = FileSystems.newFileSystem(zipUri, env)) {
+ Path dirInZipPath = zipFs.getPath(this.path.toString());
+ if (Files.notExists(dirInZipPath)) {
+ Files.createDirectories(dirInZipPath);
+
+ // To ensure the directory is actually added to the ZIP, we
+ // might need to add a temporary file
+ // in this directory. This is a workaround and should be used
+ // with caution.
+ Path tempFileInDir = dirInZipPath.resolve(".keep"); //$NON-NLS-1$
+ Files.createFile(tempFileInDir);
+
+ // Immediately delete the temporary file after creation to just
+ // keep the directory
+ Files.delete(tempFileInDir);
+ }
+ } catch (IOException e) {
+ throw new CoreException(new Status(IStatus.ERROR, "org.eclipse.core.filesystem.zip", "Error creating directory in ZIP file", e)); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ // Return a file store representing the newly created directory.
+ return new ZipFileStore(rootStore, this.path);
+ }
+
+ @Override
+ public void move(IFileStore destination, int options, IProgressMonitor monitor) throws CoreException {
+ if (!(destination instanceof ZipFileStore)) {
+ super.move(destination, options, monitor);
+ return;
+ }
+ ZipFileStore destZipFileStore = (ZipFileStore) destination;
+
+ try (FileSystem srcFs = openZipFileSystem(); FileSystem destFs = destZipFileStore.openZipFileSystem()) {
+ Path srcPath = srcFs.getPath(this.path.toString());
+ Path destPath = destFs.getPath(destZipFileStore.path.toString());
+
+ if (destPath.getParent() != null) {
+ Files.createDirectories(destPath.getParent());
+ }
+
+ if (Files.isDirectory(srcPath)) {
+ moveDirectory(srcPath, destPath, srcFs, destFs);
+ } else {
+ Files.move(srcPath, destPath, StandardCopyOption.REPLACE_EXISTING);
+ }
+ } catch (IOException | URISyntaxException e) {
+ throw new CoreException(new Status(IStatus.ERROR, "org.eclipse.core.filesystem.zip", "Error moving entry within ZIP", e)); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ private void moveDirectory(Path srcPath, Path destPath, FileSystem srcFs, FileSystem destFs) throws IOException {
+ // Ensure the destination directory structure is ready
+ if (destPath.getParent() != null) {
+ Files.createDirectories(destPath.getParent());
+ }
+
+ // Recursively move the contents
+ Files.walk(srcPath).forEach(source -> {
+ try {
+ Path destination = destPath.resolve(srcPath.relativize(source));
+ if (Files.isDirectory(source)) {
+ if (!Files.exists(destination)) {
+ Files.createDirectories(destination);
+ }
+ } else {
+ Files.move(source, destination, StandardCopyOption.REPLACE_EXISTING);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to move files", e); //$NON-NLS-1$
+ }
+ });
+
+ // Delete the source directory after moving its contents
+ Files.walk(srcPath).sorted(Comparator.reverseOrder()).forEach(pathToMove -> {
+ try {
+ Files.delete(pathToMove);
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to delete original files after move", e); //$NON-NLS-1$
+ }
+ });
+ }
+
+ @Override
+ public InputStream openInputStream(int options, IProgressMonitor monitor) throws CoreException {
+ try {
+ ZipInputStream in = new ZipInputStream(rootStore.openInputStream(EFS.NONE, monitor));
+ ZipEntry entry = findEntry(path.toString(), in);
+ if (entry == null) {
+ throw new CoreException(Status.error("File not found: " + rootStore.toString())); //$NON-NLS-1$
+ }
+ if (entry.isDirectory()) {
+ throw new CoreException(Status.error("Resource is not a file: " + rootStore.toString())); //$NON-NLS-1$
+ }
+ return in;
+ } catch (IOException e) {
+ throw new CoreException(Status.error("Could not read file: " + rootStore.toString(), e)); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public OutputStream openOutputStream(int options, IProgressMonitor monitor) {
+ // Creating a ByteArrayOutputStream to capture the data written to the
+ // OutputStream
+ ByteArrayOutputStream baos = new ByteArrayOutputStream() {
+ @Override
+ public void close() throws IOException {
+ try (FileSystem zipFs = openZipFileSystem()) {
+ Path entryPath = zipFs.getPath(path.toString());
+ // Ensure parent directories exist
+ Path parentPath = entryPath.getParent();
+ if (parentPath != null) {
+ Files.createDirectories(parentPath);
+ }
+ // Write the ByteArrayOutputStream's data to the entry
+ // in the ZIP file
+ Files.write(entryPath, this.toByteArray(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
+
+ } catch (Exception e) {
+ throw new IOException("Failed to integrate data into ZIP file", e); //$NON-NLS-1$
+ }
+ }
+ };
+
+ return baos;
+ }
+
+ private FileSystem openZipFileSystem() throws URISyntaxException, IOException {
+ Map env = new HashMap<>();
+ env.put("create", "false"); //$NON-NLS-1$ //$NON-NLS-2$
+ URI nioURI = toNioURI();
+ Path innerArchivePath = null;
+
+ if (isNested()) {
+ ZipFileStore outerZipFileStore = (ZipFileStore) this.rootStore;
+ FileSystem outerFs = outerZipFileStore.openZipFileSystem();
+ innerArchivePath = outerFs.getPath(outerZipFileStore.path.toString());
+ nioURI = innerArchivePath.toUri();
+ }
+
+ try {
+ if (innerArchivePath != null) {
+ return FileSystems.newFileSystem(innerArchivePath, env);
+ }
+ return FileSystems.newFileSystem(nioURI, env);
+ } catch (FileSystemAlreadyExistsException e) {
+ return FileSystems.getFileSystem(nioURI);
+ }
+ }
+
+ @Override
+ public void putInfo(IFileInfo info, int options, IProgressMonitor monitor) throws CoreException {
+ if (monitor != null) {
+ monitor.beginTask("Updating Zip Entry Information", 1); //$NON-NLS-1$
+ }
+ try (FileSystem zipFs = openZipFileSystem()) {
+ Path filePath = zipFs.getPath(path.toString());
+ // Check options for what information is requested to be updated
+ if ((options & EFS.SET_ATTRIBUTES) != 0) {
+ boolean isHidden = info.getAttribute(EFS.ATTRIBUTE_HIDDEN);
+ boolean isArchive = info.getAttribute(EFS.ATTRIBUTE_ARCHIVE);
+
+ if (ZipFileSystem.getOS().startsWith("Windows")) { //$NON-NLS-1$
+ Files.setAttribute(filePath, "dos:hidden", isHidden); //$NON-NLS-1$
+ Files.setAttribute(filePath, "dos:archive", isArchive); //$NON-NLS-1$
+ }
+ }
+ if ((options & EFS.SET_LAST_MODIFIED) != 0) {
+ FileTime lastModified = FileTime.fromMillis(info.getLastModified());
+ Files.setLastModifiedTime(filePath, lastModified);
+ }
+
+ } catch (Exception e) {
+ throw new CoreException(new Status(IStatus.ERROR, getPluginId(), "Error updating ZIP file entry information", e)); //$NON-NLS-1$
+ } finally {
+ if (monitor != null) {
+ monitor.done();
+ }
+ }
+ }
+
+ @Override
+ public URI toURI() {
+ String scheme = ZipFileSystem.SCHEME_ZIP;
+ String pathString = path.makeAbsolute().toString();
+ URI rootStoreURI = rootStore.toURI();
+ String rootStoreScheme = rootStoreURI.getScheme();
+ String rootStorePath = rootStoreURI.getPath();
+ String rootStoreQuery = rootStoreScheme + ":" + rootStorePath; //$NON-NLS-1$
+ try {
+ return new URI(scheme, null, pathString, rootStoreQuery, null);
+ } catch (URISyntaxException e) {
+ // should not happen
+ throw new RuntimeException(e);
+ }
+ }
+
+ private URI toNioURI() throws URISyntaxException {
+ String nioScheme = "jar:"; //$NON-NLS-1$
+ String rootPath = rootStore.toURI().toString();
+
+ String suffix = "!/"; //$NON-NLS-1$
+ String ret = nioScheme + rootPath + suffix;
+ return new URI(ret);
+ }
+
+}
diff --git a/resources/examples/org.eclipse.ui.examples.filesystem/src/org/eclipse/core/internal/filesystem/zip/ZipFileSystem.java b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/zip/ZipFileSystem.java
similarity index 79%
rename from resources/examples/org.eclipse.ui.examples.filesystem/src/org/eclipse/core/internal/filesystem/zip/ZipFileSystem.java
rename to resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/zip/ZipFileSystem.java
index 386fdda01ef..b030d13ddc7 100644
--- a/resources/examples/org.eclipse.ui.examples.filesystem/src/org/eclipse/core/internal/filesystem/zip/ZipFileSystem.java
+++ b/resources/bundles/org.eclipse.core.filesystem/src/org/eclipse/core/internal/filesystem/zip/ZipFileSystem.java
@@ -21,6 +21,9 @@
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
+/**
+ * @since 1.11
+ */
public class ZipFileSystem extends FileSystem {
/**
* Scheme constant (value "zip") indicating the zip file system scheme.
@@ -41,4 +44,22 @@ public IFileStore getStore(URI uri) {
}
return EFS.getNullFileSystem().getStore(uri);
}
+
+ /**
+ * Returns the current OS. This is equivalent to Platform.getOS(), but
+ * is tolerant of the platform runtime not being present.
+ */
+ static String getOS() {
+ return System.getProperty("osgi.os", ""); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ @Override
+ public boolean canDelete() {
+ return true;
+ }
+
+ @Override
+ public boolean canWrite() {
+ return true;
+ }
}
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 cff283ec254..7bb930abfb4 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.20.200.qualifier
+Bundle-Version: 3.21.0.qualifier
Bundle-Activator: org.eclipse.core.resources.ResourcesPlugin
Bundle-Vendor: %providerName
Bundle-Localization: plugin
diff --git a/resources/bundles/org.eclipse.core.resources/plugin.xml b/resources/bundles/org.eclipse.core.resources/plugin.xml
index 74b386a109c..9cdeba8cce4 100644
--- a/resources/bundles/org.eclipse.core.resources/plugin.xml
+++ b/resources/bundles/org.eclipse.core.resources/plugin.xml
@@ -203,6 +203,12 @@
class="org.eclipse.core.internal.propertytester.ResourceMappingPropertyTester"
properties="projectPersistentProperty"
id="org.eclipse.core.resources.mappingPropertyTester"/>
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
entries = new HashMap<>();
- String myName = path.toString();
- try (ZipInputStream in = new ZipInputStream(rootStore.openInputStream(EFS.NONE, monitor))) {
- ZipEntry current;
- while ((current = in.getNextEntry()) != null) {
- final String currentPath = current.getName();
- if (isParent(myName, currentPath)) {
- entries.put(currentPath, current);
- } else if (isAncestor(myName, currentPath)) {
- int myNameLength = myName.length() + 1;
- int nameEnd = currentPath.indexOf('/', myNameLength);
- String dirName = nameEnd == -1 ? currentPath : currentPath.substring(0, nameEnd + 1);
- if (!entries.containsKey(dirName))
- entries.put(dirName, new ZipEntry(dirName));
- }
- }
- } catch (IOException e) {
- throw new CoreException(Status.error("Could not read file: " + rootStore.toString(), e));
- }
- return entries.values().toArray(new ZipEntry[entries.size()]);
- }
-
- @Override
- public IFileInfo[] childInfos(int options, IProgressMonitor monitor) throws CoreException {
- ZipEntry[] entries = childEntries(monitor);
- int entryCount = entries.length;
- IFileInfo[] infos = new IFileInfo[entryCount];
- for (int i = 0; i < entryCount; i++) {
- infos[i] = convertZipEntryToFileInfo(entries[i]);
- }
- return infos;
- }
-
- @Override
- public String[] childNames(int options, IProgressMonitor monitor) throws CoreException {
- ZipEntry[] entries = childEntries(monitor);
- int entryCount = entries.length;
- String[] names = new String[entryCount];
- for (int i = 0; i < entryCount; i++) {
- names[i] = computeName(entries[i]);
- }
- return names;
- }
-
- /**
- * Computes the simple file name for a given zip entry.
- */
- private String computeName(ZipEntry entry) {
- //the entry name is a relative path, with an optional trailing separator
- //We need to strip off the trailing slash, and then take everything after the
- //last separator as the name
- String name = entry.getName();
- int end = name.length() - 1;
- if (name.charAt(end) == '/') {
- end--;
- }
- return name.substring(name.lastIndexOf('/', end) + 1, end + 1);
- }
-
- /**
- * Creates a file info object corresponding to a given zip entry
- *
- * @param entry the zip entry
- * @return The file info for a zip entry
- */
- private IFileInfo convertZipEntryToFileInfo(ZipEntry entry) {
- FileInfo info = new FileInfo(computeName(entry));
- info.setLastModified(entry.getTime());
- info.setExists(true);
- info.setDirectory(entry.isDirectory());
- info.setLength(entry.getSize());
- return info;
- }
-
- @Override
- public IFileInfo fetchInfo(int options, IProgressMonitor monitor) throws CoreException {
- try (ZipInputStream in = new ZipInputStream(rootStore.openInputStream(EFS.NONE, monitor))) {
- String myPath = path.toString();
- ZipEntry current;
- while ((current = in.getNextEntry()) != null) {
- String currentPath = current.getName();
- if (myPath.equals(currentPath)) {
- return convertZipEntryToFileInfo(current);
- }
- //directories don't always have their own entry, but it is implied by the existence of a child
- if (isAncestor(myPath, currentPath)) {
- return createDirectoryInfo(getName());
- }
- }
- } catch (IOException e) {
- throw new CoreException(Status.error("Could not read file: " + rootStore.toString(), e));
- }
- //does not exist
- return new FileInfo(getName());
- }
-
- /**
- * @return A directory info for this file store
- */
- private IFileInfo createDirectoryInfo(String name) {
- FileInfo result = new FileInfo(name);
- result.setExists(true);
- result.setDirectory(true);
- return result;
- }
-
- /**
- * Finds the zip entry with the given name in this zip file. Returns the
- * entry and leaves the input stream open positioned at the beginning of
- * the bytes of that entry. Returns null if the entry could not be found.
- */
- private ZipEntry findEntry(String name, ZipInputStream in) throws IOException {
- ZipEntry current;
- while ((current = in.getNextEntry()) != null) {
- if (current.getName().equals(name)) {
- return current;
- }
- }
- return null;
- }
-
- @Override
- public IFileStore getChild(String name) {
- return new ZipFileStore(rootStore, path.append(name));
- }
-
- @Override
- public String getName() {
- String name = path.lastSegment();
- return name == null ? "" : name; //$NON-NLS-1$
- }
-
- @Override
- public IFileStore getParent() {
- if (path.segmentCount() > 0) {
- return new ZipFileStore(rootStore, path.removeLastSegments(1));
- }
- //the root entry has no parent
- return null;
- }
-
- /**
- * Returns whether ancestor is a parent of child.
- * @param ancestor the potential ancestor
- * @param child the potential child
- * @return true
or false
- */
- private boolean isAncestor(String ancestor, String child) {
- //children will start with myName and have no child path
- int ancestorLength = ancestor.length();
- if (ancestorLength == 0) {
- return true;
- }
- return child.startsWith(ancestor) && child.length() > ancestorLength && child.charAt(ancestorLength) == '/';
- }
-
- /**
- * Returns whether parent is the immediate parent of child.
- * @param parent the potential parent
- * @param child the potential child
- * @return true
or false
- */
- private boolean isParent(String parent, String child) {
- //children will start with myName and have no child path
- int chop = parent.length() + 1;
- return child.startsWith(parent) && child.length() > chop && child.substring(chop).indexOf('/') == -1;
- }
-
- @Override
- public InputStream openInputStream(int options, IProgressMonitor monitor) throws CoreException {
- try (ZipInputStream in = new ZipInputStream(rootStore.openInputStream(EFS.NONE, monitor))) {
- ZipEntry entry = findEntry(path.toString(), in);
- if (entry == null) {
- throw new CoreException(Status.error("File not found: " + rootStore.toString()));
- }
- if (entry.isDirectory()) {
- throw new CoreException(Status.error("Resource is not a file: " + rootStore.toString()));
- }
- return in;
- } catch (IOException e) {
- throw new CoreException(Status.error("Could not read file: " + rootStore.toString(), e));
- }
- }
-
- @Override
- public URI toURI() {
- try {
- return new URI(ZipFileSystem.SCHEME_ZIP, null, path.makeAbsolute().toString(), rootStore.toURI().toString(), null);
- } catch (URISyntaxException e) {
- //should not happen
- throw new RuntimeException(e);
- }
- }
-}
diff --git a/resources/examples/org.eclipse.ui.examples.filesystem/src/org/eclipse/core/internal/filesystem/zip/ZipFileSystemContributor.java b/resources/examples/org.eclipse.ui.examples.filesystem/src/org/eclipse/core/internal/filesystem/zip/ZipFileSystemContributor.java
deleted file mode 100644
index d8516a8b60a..00000000000
--- a/resources/examples/org.eclipse.ui.examples.filesystem/src/org/eclipse/core/internal/filesystem/zip/ZipFileSystemContributor.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2022 IBM Corporation 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:
- * IBM Corporation - initial API and implementation
- *******************************************************************************/
-
-package org.eclipse.core.internal.filesystem.zip;
-
-import java.io.File;
-import java.net.URI;
-import java.net.URISyntaxException;
-
-import org.eclipse.swt.widgets.FileDialog;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.ui.ide.fileSystem.FileSystemContributor;
-
-/**
- * ZipFileSystemContributor is the zip example of a file system contributor.
- */
-public class ZipFileSystemContributor extends FileSystemContributor {
-
- public ZipFileSystemContributor() {
- super();
- }
-
- @Override
- public URI getURI(String pathString) {
- try {
- if (pathString.startsWith(ZipFileSystem.SCHEME_ZIP))
- return new URI(pathString);
- } catch (URISyntaxException e1) {
- return null;
- }
- if (File.separatorChar != '/')
- pathString = pathString.replace(File.separatorChar, '/');
- final int length = pathString.length();
- StringBuffer pathBuf = new StringBuffer(length + 1);
- pathBuf.append("file:"); //$NON-NLS-1$
- // There must be a leading slash in a hierarchical URI
- if (length > 0 && (pathString.charAt(0) != '/'))
- pathBuf.append('/');
- // additional double-slash for UNC paths to distinguish from host
- // separator
- if (pathString.startsWith("//")) //$NON-NLS-1$
- pathBuf.append('/').append('/');
- pathBuf.append(pathString);
- try {
- //scheme, host, path, query, fragment
- return new URI(ZipFileSystem.SCHEME_ZIP, null, "/", pathBuf.toString(), null); //$NON-NLS-1$
- } catch (URISyntaxException e) {
- return null;
- }
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ui.ide.fileSystem.FileSystemContributor#browseFileSystem(java.lang.String, org.eclipse.swt.widgets.Shell)
- */
- @Override
- public URI browseFileSystem(String initialPath, Shell shell) {
-
- FileDialog dialog = new FileDialog(shell);
-
- if (initialPath.length() > 0)
- dialog.setFilterPath(initialPath);
-
- dialog.setFilterExtensions(new String[] {"*.zip"});//$NON-NLS-1$
-
- String selectedFile = dialog.open();
- if (selectedFile == null)
- return null;
- return getURI(selectedFile);
- }
-
-}
diff --git a/resources/examples/org.eclipse.ui.examples.filesystem/src/org/eclipse/ui/examples/filesystem/CollapseZipHandler.java b/resources/examples/org.eclipse.ui.examples.filesystem/src/org/eclipse/ui/examples/filesystem/CollapseZipHandler.java
deleted file mode 100644
index 9b75ba8bf0d..00000000000
--- a/resources/examples/org.eclipse.ui.examples.filesystem/src/org/eclipse/ui/examples/filesystem/CollapseZipHandler.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2022 IBM Corporation 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:
- * IBM Corporation - initial API and implementation
- * Patrick Ziegler - Migration from a JFace Action to a Command Handler,
- * in order to be used with the 'org.eclipse.ui.menus'
- * extension point.
- *******************************************************************************/
-package org.eclipse.ui.examples.filesystem;
-
-import java.net.URI;
-import org.eclipse.core.commands.AbstractHandler;
-import org.eclipse.core.commands.ExecutionEvent;
-import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.core.filesystem.EFS;
-import org.eclipse.core.filesystem.IFileStore;
-import org.eclipse.core.filesystem.URIUtil;
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IFolder;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.ui.handlers.HandlerUtil;
-
-public class CollapseZipHandler extends AbstractHandler {
-
- private void collapseZip(IFolder folder, Shell shell) {
- try {
- URI zipURI = new URI(folder.getLocationURI().getQuery());
- //check if the zip file is physically stored below the folder in the workspace
- IFileStore parentStore = EFS.getStore(folder.getParent().getLocationURI());
- URI childURI = parentStore.getChild(folder.getName()).toURI();
- if (URIUtil.equals(zipURI, childURI)) {
- //the zip file is in the workspace so just delete the link
- // and refresh the parent to create the resource
- folder.delete(IResource.NONE, null);
- folder.getParent().refreshLocal(IResource.DEPTH_INFINITE, null);
- } else {
- //otherwise the zip file must be a linked resource
- IFile file = folder.getParent().getFile(IPath.fromOSString(folder.getName()));
- file.createLink(zipURI, IResource.REPLACE, null);
- }
- } catch (Exception e) {
- MessageDialog.openError(shell, "Error", "Error opening zip file");
- e.printStackTrace();
- }
- }
-
- @Override
- public Object execute(ExecutionEvent event) throws ExecutionException {
- Shell shell = HandlerUtil.getActiveShell(event);
- ISelection selection = HandlerUtil.getCurrentSelection(event);
-
- if (!(selection instanceof IStructuredSelection)) {
- return null;
- }
-
- Object element = ((IStructuredSelection) selection).getFirstElement();
-
- if (!(element instanceof IFolder)) {
- return null;
- }
-
- collapseZip((IFolder) element, shell);
- return null;
- }
-
-}
diff --git a/resources/examples/org.eclipse.ui.examples.filesystem/src/org/eclipse/ui/examples/filesystem/ExpandZipHandler.java b/resources/examples/org.eclipse.ui.examples.filesystem/src/org/eclipse/ui/examples/filesystem/ExpandZipHandler.java
deleted file mode 100644
index 7fde7131080..00000000000
--- a/resources/examples/org.eclipse.ui.examples.filesystem/src/org/eclipse/ui/examples/filesystem/ExpandZipHandler.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2022 IBM Corporation 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:
- * IBM Corporation - initial API and implementation
- * Patrick Ziegler - Migration from a JFace Action to a Command Handler,
- * in order to be used with the 'org.eclipse.ui.menus'
- * extension point.
- *******************************************************************************/
-package org.eclipse.ui.examples.filesystem;
-
-import java.net.URI;
-import org.eclipse.core.commands.AbstractHandler;
-import org.eclipse.core.commands.ExecutionEvent;
-import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.core.internal.filesystem.zip.ZipFileSystem;
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IFolder;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.ui.handlers.HandlerUtil;
-
-public class ExpandZipHandler extends AbstractHandler {
-
- private void expandZip(IFile file, Shell shell) {
- try {
- URI zipURI = new URI(ZipFileSystem.SCHEME_ZIP, null, "/", file.getLocationURI().toString(), null);
- IFolder link = file.getParent().getFolder(IPath.fromOSString(file.getName()));
- link.createLink(zipURI, IResource.REPLACE, null);
- } catch (Exception e) {
- MessageDialog.openError(shell, "Error", "Error opening zip file");
- e.printStackTrace();
- }
- }
-
- @Override
- public Object execute(ExecutionEvent event) throws ExecutionException {
- Shell shell = HandlerUtil.getActiveShell(event);
- ISelection selection = HandlerUtil.getCurrentSelection(event);
-
- if (!(selection instanceof IStructuredSelection)) {
- return null;
- }
-
- Object element = ((IStructuredSelection) selection).getFirstElement();
-
- if (!(element instanceof IFile)) {
- return null;
- }
-
- expandZip((IFile) element, shell);
- return null;
- }
-
-}
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 89934875b60..8ff40f6c1bb 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
@@ -38,6 +38,8 @@ Import-Package: org.assertj.core.api,
org.junit.jupiter.api,
org.junit.jupiter.api.extension,
org.junit.jupiter.api.io,
+ org.junit.jupiter.params;version="[5.10.0,6.0.0]",
+ org.junit.jupiter.params.provider;version="[5.10.0,6.0.0]",
org.junit.platform.suite.api,
org.mockito
Bundle-ActivationPolicy: lazy
diff --git a/resources/tests/org.eclipse.core.tests.resources/resources/ZipFileSystem/BasicText.zip b/resources/tests/org.eclipse.core.tests.resources/resources/ZipFileSystem/BasicText.zip
new file mode 100644
index 00000000000..b33117fa405
Binary files /dev/null and b/resources/tests/org.eclipse.core.tests.resources/resources/ZipFileSystem/BasicText.zip differ
diff --git a/resources/tests/org.eclipse.core.tests.resources/resources/ZipFileSystem/BasicTextNew.zip b/resources/tests/org.eclipse.core.tests.resources/resources/ZipFileSystem/BasicTextNew.zip
new file mode 100644
index 00000000000..b33117fa405
Binary files /dev/null and b/resources/tests/org.eclipse.core.tests.resources/resources/ZipFileSystem/BasicTextNew.zip differ
diff --git a/resources/tests/org.eclipse.core.tests.resources/resources/ZipFileSystem/DeepNested.zip b/resources/tests/org.eclipse.core.tests.resources/resources/ZipFileSystem/DeepNested.zip
new file mode 100644
index 00000000000..4a65ed604fe
Binary files /dev/null and b/resources/tests/org.eclipse.core.tests.resources/resources/ZipFileSystem/DeepNested.zip differ
diff --git a/resources/tests/org.eclipse.core.tests.resources/resources/ZipFileSystem/Empty.zip b/resources/tests/org.eclipse.core.tests.resources/resources/ZipFileSystem/Empty.zip
new file mode 100644
index 00000000000..15cb0ecb3e2
Binary files /dev/null and b/resources/tests/org.eclipse.core.tests.resources/resources/ZipFileSystem/Empty.zip differ
diff --git a/resources/tests/org.eclipse.core.tests.resources/resources/ZipFileSystem/Fake.zip b/resources/tests/org.eclipse.core.tests.resources/resources/ZipFileSystem/Fake.zip
new file mode 100644
index 00000000000..945948d8236
--- /dev/null
+++ b/resources/tests/org.eclipse.core.tests.resources/resources/ZipFileSystem/Fake.zip
@@ -0,0 +1 @@
+THIS IS NOT A ZIP!
\ No newline at end of file
diff --git a/resources/tests/org.eclipse.core.tests.resources/resources/ZipFileSystem/NestedZipFileParent.zip b/resources/tests/org.eclipse.core.tests.resources/resources/ZipFileSystem/NestedZipFileParent.zip
new file mode 100644
index 00000000000..6af194f1ce7
Binary files /dev/null and b/resources/tests/org.eclipse.core.tests.resources/resources/ZipFileSystem/NestedZipFileParent.zip differ
diff --git a/resources/tests/org.eclipse.core.tests.resources/resources/ZipFileSystem/PasswordProtected.zip b/resources/tests/org.eclipse.core.tests.resources/resources/ZipFileSystem/PasswordProtected.zip
new file mode 100644
index 00000000000..6030f241b4a
Binary files /dev/null and b/resources/tests/org.eclipse.core.tests.resources/resources/ZipFileSystem/PasswordProtected.zip differ
diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/AllZipFileSystemTests.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/AllZipFileSystemTests.java
new file mode 100644
index 00000000000..f54297acd23
--- /dev/null
+++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/AllZipFileSystemTests.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Vector Informatik GmbH 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: Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.core.tests.filesystem.zip;
+
+import org.junit.platform.suite.api.SelectClasses;
+import org.junit.platform.suite.api.Suite;
+
+/**
+ * Class for collecting all test classes that deal with the zip file system API.
+ */
+@Suite
+@SelectClasses({ CloseTest.class, CopyTest.class, CreateTest.class, DeleteTest.class, MoveTest.class,
+ RenameTest.class, SetupTest.class, OpenTest.class })
+public class AllZipFileSystemTests {
+}
+
diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/CloseTest.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/CloseTest.java
new file mode 100644
index 00000000000..b253f49d72f
--- /dev/null
+++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/CloseTest.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Vector Informatik GmbH 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: Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.core.tests.filesystem.zip;
+
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.ensureExists;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+public class CloseTest {
+
+ @BeforeEach
+ public void setup() throws Exception {
+ ZipFileSystemTestSetup.defaultSetup();
+ }
+
+ @AfterEach
+ public void teardown() throws Exception {
+ ZipFileSystemTestSetup.teardown();
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testCloseZipFile(String zipFileName) throws Exception {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject
+ .getFolder(zipFileName);
+ ensureExists(openedZipFile);
+ ZipFileSystemTestUtil.closeZipFile(openedZipFile);
+ IFile zipFile = ZipFileSystemTestSetup.firstProject.getFile(zipFileName);
+ // Don't use Utility method ensureDoesNotExist because the fileStore is still
+ // available after closing. The fileStore is the File itself in the local file
+ // system that still exists after closing.
+ assertTrue("folder was not properly deleted: " + openedZipFile, !openedZipFile.exists());
+ ensureExists(zipFile);
+ }
+
+}
diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/CopyTest.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/CopyTest.java
new file mode 100644
index 00000000000..9c59a41dd32
--- /dev/null
+++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/CopyTest.java
@@ -0,0 +1,211 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Vector Informatik GmbH 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: Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.core.tests.filesystem.zip;
+
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.assertTextFileContent;
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.ensureDoesNotExist;
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.ensureExists;
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.getMonitor;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+/**
+ *
+ */
+public class CopyTest {
+
+ @BeforeEach
+ public void setup() throws Exception {
+ ZipFileSystemTestSetup.defaultSetup();
+ }
+
+ @AfterEach
+ public void teardown() throws Exception {
+ ZipFileSystemTestSetup.teardown();
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testCopyZipFile(String zipFileName) throws Exception {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject
+ .getFolder(zipFileName);
+ ensureExists(openedZipFile);
+ IFolder destinationFolder = ZipFileSystemTestSetup.firstProject.getFolder("Folder");
+ destinationFolder.create(true, true, getMonitor());
+ ensureExists(destinationFolder);
+ IFolder copyDestination = ZipFileSystemTestSetup.firstProject
+ .getFolder("Folder" + "/" + zipFileName);
+ openedZipFile.copy(copyDestination.getFullPath(), true, getMonitor());
+ ensureExists(copyDestination);
+ ensureExists(openedZipFile);
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testCopyFileInsideOfZipFile(String zipFileName) throws Exception {
+ IFile textFile = ZipFileSystemTestSetup.firstProject.getFile(
+ zipFileName + "/" + ZipFileSystemTestSetup.TEXT_FILE_NAME);
+ ensureExists(textFile);
+ IFolder destinationFolder = ZipFileSystemTestSetup.firstProject.getFolder("Folder");
+ destinationFolder.create(true, true, getMonitor());
+ ensureExists(destinationFolder);
+ IFile copyDestination = ZipFileSystemTestSetup.firstProject
+ .getFile("Folder" + "/" + ZipFileSystemTestSetup.TEXT_FILE_NAME);
+ textFile.copy(copyDestination.getFullPath(), true, getMonitor());
+ ensureExists(copyDestination);
+ ensureExists(textFile);
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testCopyFolderInsideOfZipFile(String zipFileName) throws Exception {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName);
+ ensureExists(openedZipFile);
+ IFolder newFolder = ZipFileSystemTestSetup.firstProject.getFolder("NewFolder");
+ ensureDoesNotExist(newFolder);
+ newFolder.create(false, true, getMonitor());
+ ensureExists(newFolder);
+ IFile textFile = newFolder.getFile("NewFile.txt");
+ ensureDoesNotExist(textFile);
+ String text = "Foo";
+ InputStream stream = new ByteArrayInputStream(text.getBytes());
+ textFile.create(stream, true, getMonitor());
+ stream.close();
+ ensureExists(textFile);
+ IFolder copyDestination = openedZipFile.getFolder("NewFolder");
+ ensureDoesNotExist(copyDestination);
+ newFolder.copy(copyDestination.getFullPath(), true, getMonitor());
+ ensureExists(copyDestination);
+ ensureExists(newFolder);
+ assertTextFileContent(textFile, "Foo");
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testCopyFileIntoZipFile(String zipFileName) throws Exception {
+ IFile textFile = ZipFileSystemTestSetup.firstProject.getFile("NewFile.txt");
+ ensureDoesNotExist(textFile);
+ String text = "Foo";
+ InputStream stream = new ByteArrayInputStream(text.getBytes());
+ textFile.create(stream, true, getMonitor());
+ stream.close();
+ ensureExists(textFile);
+ IFile copyDestination = ZipFileSystemTestSetup.firstProject
+ .getFile(zipFileName + "/" + "NewFile.txt");
+ textFile.copy(copyDestination.getFullPath(), true, getMonitor());
+ ensureExists(copyDestination);
+ ensureExists(textFile);
+ assertTextFileContent(textFile, "Foo");
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testCopyFolderIntoZipFile(String zipFileName) throws Exception {
+ IFile textFile = ZipFileSystemTestSetup.firstProject.getFile("NewFile.txt");
+ ensureDoesNotExist(textFile);
+ String text = "Foo";
+ InputStream stream = new ByteArrayInputStream(text.getBytes());
+ textFile.create(stream, true, getMonitor());
+ stream.close();
+ ensureExists(textFile);
+ IFile copyDestination = ZipFileSystemTestSetup.firstProject.getFile(zipFileName + "/" + "NewFile.txt");
+ textFile.copy(copyDestination.getFullPath(), true, getMonitor());
+ ensureExists(copyDestination);
+ ensureExists(textFile);
+ assertTextFileContent(textFile, "Foo");
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testCopyFileFromOutsideOfZipFIleIntoFolderInZipFile(String zipFileName) throws Exception {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName);
+ IFolder newFolder = openedZipFile.getFolder("NewFolder");
+ ensureDoesNotExist(newFolder);
+ newFolder.create(false, true, getMonitor());
+ ensureExists(newFolder);
+ IFile textFile = ZipFileSystemTestSetup.firstProject.getFile("NewFile.txt");
+ ensureDoesNotExist(textFile);
+ String text = "Foo";
+ InputStream stream = new ByteArrayInputStream(text.getBytes());
+ textFile.create(stream, true, getMonitor());
+ stream.close();
+ ensureExists(textFile);
+ IFile copyDestination = newFolder.getFile("NewFile.txt");
+ ensureDoesNotExist(copyDestination);
+ textFile.copy(copyDestination.getFullPath(), true, getMonitor());
+ ensureExists(copyDestination);
+ ensureExists(textFile);
+ assertTextFileContent(textFile, "Foo");
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testCopyFolderIntoFolderInZipFile(String zipFileName) throws Exception {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName);
+ IFolder firstNewFolder = openedZipFile.getFolder("FirstNewFolder");
+ ensureDoesNotExist(firstNewFolder);
+ firstNewFolder.create(false, true, getMonitor());
+ ensureExists(firstNewFolder);
+ IFolder secondNewFolder = openedZipFile.getFolder("SecondNewFolder");
+ ensureDoesNotExist(secondNewFolder);
+ secondNewFolder.create(false, true, getMonitor());
+ ensureExists(secondNewFolder);
+ IFile textFile = firstNewFolder.getFile("NewFile.txt");
+ ensureDoesNotExist(textFile);
+ String text = "Foo";
+ try (InputStream stream = new ByteArrayInputStream(text.getBytes())) {
+ textFile.create(stream, true, getMonitor());
+ }
+ ensureExists(textFile);
+ IFolder copyDestination = secondNewFolder.getFolder("FirstNewFolder");
+ ensureDoesNotExist(copyDestination);
+ firstNewFolder.copy(copyDestination.getFullPath(), true, getMonitor());
+ ensureExists(copyDestination);
+ ensureExists(firstNewFolder);
+ assertTextFileContent(textFile, "Foo");
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testCopyFileFromOneFolderToOtherFolderInsideofZipFile(String zipFileName) throws Exception {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName);
+ IFolder firstNewFolder = openedZipFile.getFolder("FirstNewFolder");
+ ensureDoesNotExist(firstNewFolder);
+ firstNewFolder.create(false, true, getMonitor());
+ ensureExists(firstNewFolder);
+ IFolder secondNewFolder = openedZipFile.getFolder("SecondNewFolder");
+ ensureDoesNotExist(secondNewFolder);
+ secondNewFolder.create(false, true, getMonitor());
+ ensureExists(secondNewFolder);
+ IFile textFile = firstNewFolder.getFile("NewFile.txt");
+ ensureDoesNotExist(textFile);
+ String text = "Foo";
+ try (InputStream stream = new ByteArrayInputStream(text.getBytes())) {
+ textFile.create(stream, true, getMonitor());
+ }
+ ensureExists(textFile);
+ IFile copyDestination = secondNewFolder.getFile("NewFile.txt");
+ ensureDoesNotExist(copyDestination);
+ textFile.copy(copyDestination.getFullPath(), true, getMonitor());
+ ensureExists(copyDestination);
+ ensureExists(textFile);
+ assertTextFileContent(textFile, "Foo");
+ }
+}
diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/CreateTest.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/CreateTest.java
new file mode 100644
index 00000000000..6279bb920cb
--- /dev/null
+++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/CreateTest.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Vector Informatik GmbH 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: Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.core.tests.filesystem.zip;
+
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.assertTextFileContent;
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.ensureDoesNotExist;
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.ensureExists;
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.getMonitor;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+public class CreateTest {
+
+ @BeforeEach
+ public void setup() throws Exception {
+ ZipFileSystemTestSetup.defaultSetup();
+ }
+
+ @AfterEach
+ public void teardown() throws Exception {
+ ZipFileSystemTestSetup.teardown();
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testCreateFileInsideOfZipFile(String zipFileName) throws Exception {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName);
+ IFile textFile = openedZipFile.getFile("NewFile.txt");
+ ensureDoesNotExist(textFile);
+ String text = "Foo";
+ InputStream stream = new ByteArrayInputStream(text.getBytes());
+ textFile.create(stream, true, getMonitor());
+ stream.close();
+ ensureExists(textFile);
+ assertTextFileContent(textFile, "Foo");
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testCreateFolderInsideOfZipFile(String zipFileName) throws Exception {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName);
+ IFolder newFolder = openedZipFile.getFolder("NewFolder");
+ ensureDoesNotExist(newFolder);
+ newFolder.create(false, true, getMonitor());
+ ensureExists(newFolder);
+ }
+}
diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/DeleteTest.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/DeleteTest.java
new file mode 100644
index 00000000000..1b2736eba49
--- /dev/null
+++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/DeleteTest.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Vector Informatik GmbH 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: Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.core.tests.filesystem.zip;
+
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.ensureDoesNotExist;
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.ensureExists;
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.getMonitor;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.runtime.CoreException;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+public class DeleteTest {
+
+ @BeforeEach
+ public void setup() throws Exception {
+ ZipFileSystemTestSetup.defaultSetup();
+ }
+
+ @AfterEach
+ public void teardown() throws Exception {
+ ZipFileSystemTestSetup.teardown();
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testDeleteZipFile(String zipFileName) throws CoreException, IOException {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject
+ .getFolder(zipFileName);
+ ensureExists(openedZipFile);
+ openedZipFile.delete(false, false, getMonitor());
+ ensureDoesNotExist(openedZipFile);
+ IFile zipFile = ZipFileSystemTestSetup.firstProject.getFile(zipFileName);
+ ensureDoesNotExist(zipFile);
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testDeleteFileInsideOfZipFile(String zipFileName) throws CoreException, IOException {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject
+ .getFolder(zipFileName);
+ IFile textFile = openedZipFile.getFile(ZipFileSystemTestSetup.TEXT_FILE_NAME);
+ ensureExists(textFile);
+ textFile.delete(true, getMonitor());
+ ensureDoesNotExist(textFile);
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testDeleteEmptyFolder(String zipFileName) throws CoreException, IOException {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName);
+ IFolder folder = openedZipFile.getFolder("FolderToDelete");
+ ensureDoesNotExist(folder);
+ folder.create(true, true, getMonitor());
+ ensureExists(folder);
+ folder.delete(true, getMonitor());
+ ensureDoesNotExist(folder);
+ }
+
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testDeleteFolderWithChildren(String zipFileName) throws CoreException, IOException {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName);
+ IFolder folder = openedZipFile.getFolder("FolderToDelete");
+ ensureDoesNotExist(folder);
+ folder.create(true, true, getMonitor());
+ ensureExists(folder);
+ IFile textFile = folder.getFile(ZipFileSystemTestSetup.TEXT_FILE_NAME);
+ textFile.create(new ByteArrayInputStream("Hello World!".getBytes()), true, getMonitor());
+ ensureExists(textFile);
+ folder.delete(true, getMonitor());
+ ensureDoesNotExist(folder);
+ ensureDoesNotExist(textFile);
+ }
+}
diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/MoveTest.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/MoveTest.java
new file mode 100644
index 00000000000..8f0951cb16b
--- /dev/null
+++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/MoveTest.java
@@ -0,0 +1,298 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Vector Informatik GmbH 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: Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.core.tests.filesystem.zip;
+
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.assertTextFileContent;
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.ensureDoesNotExist;
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.ensureExists;
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.getMonitor;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.runtime.CoreException;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+
+public class MoveTest {
+
+ @BeforeEach
+ public void setup() throws Exception {
+ ZipFileSystemTestSetup.setupWithTwoProjects();
+ }
+
+ @AfterEach
+ public void teardown() throws Exception {
+ ZipFileSystemTestSetup.teardown();
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testMoveZipFileWithinProject(String zipFileName) throws CoreException, IOException {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName);
+ IFolder destinationFolder = ZipFileSystemTestSetup.firstProject.getFolder("destinationFolder");
+ destinationFolder.create(false, true, getMonitor());
+ IFolder destination = ZipFileSystemTestSetup.firstProject
+ .getFolder("destinationFolder/" + zipFileName);
+ openedZipFile.move(destination.getFullPath(), false, getMonitor());
+ IFolder newFolder = ZipFileSystemTestSetup.firstProject
+ .getFolder(destinationFolder.getName() + "/" + zipFileName);
+ ensureExists(newFolder);
+ ensureDoesNotExist(openedZipFile);
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testMoveZipFileToOtherProject(String zipFileName) throws CoreException, IOException {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName);
+ IFolder destination = ZipFileSystemTestSetup.secondProject.getFolder(zipFileName);
+ openedZipFile.move(destination.getFullPath(), false, getMonitor());
+ IFolder newFolder = ZipFileSystemTestSetup.secondProject.getFolder(zipFileName);
+ ensureExists(newFolder);
+ ensureDoesNotExist(openedZipFile);
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testMoveZipFileToOtherProjectFolder(String zipFileName) throws CoreException, IOException {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName);
+ IFolder destinationFolder = ZipFileSystemTestSetup.secondProject.getFolder("destinationFolder");
+ destinationFolder.create(false, true, getMonitor());
+ IFolder destination = ZipFileSystemTestSetup.secondProject
+ .getFolder("destinationFolder/" + zipFileName);
+ openedZipFile.move(destination.getFullPath(), false, getMonitor());
+ IFolder newFolder = ZipFileSystemTestSetup.secondProject
+ .getFolder(destinationFolder.getName() + "/" + zipFileName);
+ ensureExists(newFolder);
+ ensureDoesNotExist(openedZipFile);
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testMoveFileIntoZipFile(String zipFileName) throws Exception {
+ IFile textFile = ZipFileSystemTestSetup.firstProject.getFile("NewFile.txt");
+ ensureDoesNotExist(textFile);
+ String text = "Foo";
+ InputStream stream = new ByteArrayInputStream(text.getBytes());
+ textFile.create(stream, false, getMonitor());
+ stream.close();
+ ensureExists(textFile);
+ IFile destinationFile = ZipFileSystemTestSetup.firstProject
+ .getFile(zipFileName + "/" + "NewFile.txt");
+ textFile.move(destinationFile.getFullPath(), false, getMonitor());
+ ensureExists(destinationFile);
+ assertTextFileContent(destinationFile, text);
+ ensureDoesNotExist(textFile);
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testMoveFolderIntoZipFile(String zipFileName) throws Exception {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName);
+ IFolder destinationFolder = openedZipFile.getFolder("destinationFolder");
+ ensureDoesNotExist(destinationFolder);
+ destinationFolder.create(false, true, getMonitor());
+ ensureExists(destinationFolder);
+ IFolder newFolder = ZipFileSystemTestSetup.firstProject.getFolder("NewFolder");
+ ensureDoesNotExist(newFolder);
+ newFolder.create(false, true, getMonitor());
+ ensureExists(newFolder);
+ IFolder newFolderDestination = destinationFolder.getFolder("NewFolder");
+ newFolder.move(newFolderDestination.getFullPath(), false, getMonitor());
+ ensureDoesNotExist(newFolder);
+ ensureExists(newFolderDestination);
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testMoveFolderWithContentIntoZipFile(String zipFileName) throws Exception {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName);
+ IFolder destinationFolder = openedZipFile.getFolder("destinationFolder");
+ ensureDoesNotExist(destinationFolder);
+ destinationFolder.create(false, true, getMonitor());
+ ensureExists(destinationFolder);
+ IFolder newFolder = ZipFileSystemTestSetup.firstProject.getFolder("NewFolder");
+ ensureDoesNotExist(newFolder);
+ newFolder.create(false, true, getMonitor());
+ ensureExists(newFolder);
+ IFile textFile = newFolder.getFile("NewFile.txt");
+ ensureDoesNotExist(textFile);
+ String text = "Foo";
+ InputStream stream = new ByteArrayInputStream(text.getBytes());
+ textFile.create(stream, false, getMonitor());
+ stream.close();
+ ensureExists(textFile);
+ IFolder newFolderDestination = destinationFolder.getFolder("NewFolder");
+ newFolder.move(newFolderDestination.getFullPath(), false, getMonitor());
+ ensureDoesNotExist(newFolder);
+ ensureExists(newFolderDestination);
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testMoveFileFromZipFile(String zipFileName) throws Exception {
+ IFile textFile = ZipFileSystemTestSetup.firstProject
+ .getFile(zipFileName + "/" + ZipFileSystemTestSetup.TEXT_FILE_NAME);
+ ensureExists(textFile);
+ IFile destinationFile = ZipFileSystemTestSetup.firstProject.getFile(ZipFileSystemTestSetup.TEXT_FILE_NAME);
+ textFile.move(destinationFile.getFullPath(), false, getMonitor());
+ ensureExists(destinationFile);
+ assertTextFileContent(destinationFile, "Hello World!");
+ ensureDoesNotExist(textFile);
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testMoveFolderFromZipFile(String zipFileName) throws Exception {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName);
+ IFolder newFolder = openedZipFile.getFolder("NewFolder");
+ ensureDoesNotExist(newFolder);
+ newFolder.create(false, true, getMonitor());
+ ensureExists(newFolder);
+ IFolder folderDestination = ZipFileSystemTestSetup.firstProject.getFolder("NewFolder");
+ newFolder.move(folderDestination.getFullPath(), false, getMonitor());
+ ensureDoesNotExist(newFolder);
+ ensureExists(folderDestination);
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testMoveFolderWithContentFromZipFile(String zipFileName) throws Exception {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName);
+ IFolder newFolder = openedZipFile.getFolder("NewFolder");
+ ensureDoesNotExist(newFolder);
+ newFolder.create(false, true, getMonitor());
+ ensureExists(newFolder);
+ IFile textFile = newFolder.getFile("NewFile.txt");
+ ensureDoesNotExist(textFile);
+ String text = "Foo";
+ InputStream stream = new ByteArrayInputStream(text.getBytes());
+ textFile.create(stream, false, getMonitor());
+ stream.close();
+ ensureExists(textFile);
+ IFolder folderDestination = ZipFileSystemTestSetup.firstProject.getFolder("NewFolder");
+ newFolder.move(folderDestination.getFullPath(), false, getMonitor());
+ ensureDoesNotExist(newFolder);
+ ensureExists(folderDestination);
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testMoveFolderWithContentFromZipFileIntoOtherZipFile(String zipFileName) throws Exception {
+ IFolder firstZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName);
+ // create and open second ZipFile
+ String secondZipFileName = zipFileName.replace(".", "New.");
+ IFile secondZipFile = ZipFileSystemTestSetup.firstProject.getFile(secondZipFileName);
+ ensureDoesNotExist(secondZipFile);
+ ZipFileSystemTestSetup.copyZipFileIntoProject(ZipFileSystemTestSetup.firstProject, secondZipFileName);
+ ensureExists(secondZipFile);
+ ZipFileSystemTestUtil.openZipFile(secondZipFile);
+ IFolder openedSecondZipFile = ZipFileSystemTestSetup.firstProject.getFolder(secondZipFileName);
+ ensureExists(openedSecondZipFile);
+
+ IFolder newFolder = firstZipFile.getFolder("NewFolder");
+ ensureDoesNotExist(newFolder);
+ newFolder.create(false, true, getMonitor());
+ ensureExists(newFolder);
+ IFile textFile = newFolder.getFile("NewFile.txt");
+ ensureDoesNotExist(textFile);
+ String text = "Foo";
+ InputStream stream = new ByteArrayInputStream(text.getBytes());
+ textFile.create(stream, false, getMonitor());
+ stream.close();
+ ensureExists(textFile);
+ IFolder movedFolderDestination = openedSecondZipFile.getFolder("NewFolder");
+ newFolder.move(movedFolderDestination.getFullPath(), false, getMonitor());
+ ensureDoesNotExist(newFolder);
+ ensureExists(movedFolderDestination);
+ IFile movedTextFile = movedFolderDestination.getFile("NewFile.txt");
+ ensureExists(movedTextFile);
+ }
+
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testMoveFileInsideOfZipFile(String zipFileName) throws Exception {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName);
+ IFolder destinationFolder = openedZipFile.getFolder("destinationFolder");
+ ensureDoesNotExist(destinationFolder);
+ destinationFolder.create(false, true, getMonitor());
+ ensureExists(destinationFolder);
+ IFile textFile = openedZipFile.getFile(ZipFileSystemTestSetup.TEXT_FILE_NAME);
+ ensureExists(textFile);
+ IFile fileDestination = destinationFolder.getFile(ZipFileSystemTestSetup.TEXT_FILE_NAME);
+ ensureDoesNotExist(fileDestination);
+ textFile.move(fileDestination.getFullPath(), false, getMonitor());
+ ensureExists(fileDestination);
+ ensureDoesNotExist(textFile);
+ }
+
+
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testMoveZipFileIntoZipFile(String zipFileName) throws Exception {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName);
+ // create and open second ZipFile
+ String newZipFileName = zipFileName.replace(".", "New.");
+ IFile newZipFile = ZipFileSystemTestSetup.firstProject.getFile(newZipFileName);
+ ensureDoesNotExist(newZipFile);
+ ZipFileSystemTestSetup.copyZipFileIntoProject(ZipFileSystemTestSetup.firstProject, newZipFileName);
+ ensureExists(newZipFile);
+ ZipFileSystemTestUtil.openZipFile(newZipFile);
+ IFolder newOpenedZipFile = ZipFileSystemTestSetup.firstProject.getFolder(newZipFileName);
+ ensureExists(newOpenedZipFile);
+ // move second ZipFile into first ZipFile
+ IFile newOpenedZipFileDestination = openedZipFile.getFile(newZipFileName);
+ newOpenedZipFile.move(newOpenedZipFileDestination.getFullPath(), false, getMonitor());
+ ensureExists(newOpenedZipFileDestination);
+ ensureDoesNotExist(newOpenedZipFile);
+ }
+
+ /**
+ * When moving or expanding an opened zip file that contains a folder with
+ * content. errors can occur. This is because the local name of the resources
+ * inside the folder contains "\" seperators that are not allowed when
+ * refreshing the Workspace. This test checks if this specific error is handeled
+ * correctly in RefreshLocalVisitor#visit()
+ */
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testMoveZipFileWithFolder(String zipFileName) throws Exception {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName);
+ String contentFolderPath = zipFileName + "/" + "Folder";
+ IFolder contentFolder = ZipFileSystemTestSetup.firstProject.getFolder(contentFolderPath);
+ ensureDoesNotExist(contentFolder);
+ contentFolder.create(false, true, getMonitor());
+ ensureExists(contentFolder);
+ String text = "Foo";
+ InputStream stream = new ByteArrayInputStream(text.getBytes());
+ IFile textFile = ZipFileSystemTestSetup.firstProject.getFile(contentFolderPath + "/" + "textFile");
+ ensureDoesNotExist(textFile);
+ textFile.create(stream, false, getMonitor());
+ ensureExists(textFile);
+ IFolder destinationFolder = ZipFileSystemTestSetup.firstProject.getFolder("destinationFolder");
+ ensureDoesNotExist(destinationFolder);
+ destinationFolder.create(false, true, getMonitor());
+ ensureExists(destinationFolder);
+ IFolder zipFileDestination = ZipFileSystemTestSetup.firstProject.getFolder("destinationFolder/" + zipFileName);
+ ensureDoesNotExist(zipFileDestination);
+ openedZipFile.move(zipFileDestination.getFullPath(), false, getMonitor());
+ ensureExists(zipFileDestination);
+ }
+}
diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/OpenTest.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/OpenTest.java
new file mode 100644
index 00000000000..9aa41556312
--- /dev/null
+++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/OpenTest.java
@@ -0,0 +1,162 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Vector Informatik GmbH 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: Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.core.tests.filesystem.zip;
+
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.assertTextFileContent;
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.ensureDoesNotExist;
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.ensureExists;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class OpenTest {
+
+ @BeforeEach
+ public void setup() throws Exception {
+ ZipFileSystemTestSetup.setup(new String[] {});
+ }
+
+ @AfterEach
+ public void teardown() throws Exception {
+ ZipFileSystemTestSetup.teardown();
+ }
+
+ @Test
+ public void testOpenEmptyZipFile() throws IOException, CoreException, URISyntaxException {
+ ZipFileSystemTestSetup.copyZipFileIntoProject(ZipFileSystemTestSetup.firstProject,
+ ZipFileSystemTestSetup.EMPTY_ZIP_FILE_NAME);
+ IProject project = ZipFileSystemTestSetup.firstProject;
+ IFile zipFile = project.getFile(ZipFileSystemTestSetup.EMPTY_ZIP_FILE_NAME);
+ ensureExists(zipFile);
+
+ try {
+ ZipFileSystemTestUtil.openZipFile(zipFile);
+ } catch (CoreException e) {
+ ensureExists(zipFile);
+ assertEquals("Zip File has no children", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testOpenNestedZipFileParent() throws IOException, CoreException, URISyntaxException {
+ ZipFileSystemTestSetup.copyZipFileIntoProject(ZipFileSystemTestSetup.firstProject,
+ ZipFileSystemTestSetup.NESTED_ZIP_FILE_PARENT_NAME);
+ IFile nestedZipFileParent = ZipFileSystemTestSetup.firstProject
+ .getFile(ZipFileSystemTestSetup.NESTED_ZIP_FILE_PARENT_NAME);
+ ensureExists(nestedZipFileParent);
+ ZipFileSystemTestUtil.openZipFile(nestedZipFileParent);
+ IFolder openedNestedZipFileParent = ZipFileSystemTestSetup.firstProject
+ .getFolder(ZipFileSystemTestSetup.NESTED_ZIP_FILE_PARENT_NAME);
+ ensureExists(openedNestedZipFileParent);
+ }
+
+ @Test
+ public void testOpenNestedZipFileChild() throws IOException, CoreException, URISyntaxException {
+ ZipFileSystemTestSetup.copyZipFileIntoProject(ZipFileSystemTestSetup.firstProject,
+ ZipFileSystemTestSetup.NESTED_ZIP_FILE_PARENT_NAME);
+ IFile nestedZipFileParent = ZipFileSystemTestSetup.firstProject
+ .getFile(ZipFileSystemTestSetup.NESTED_ZIP_FILE_PARENT_NAME);
+ ensureExists(nestedZipFileParent);
+ ZipFileSystemTestUtil.openZipFile(nestedZipFileParent);
+ IFolder openedNestedZipFileParent = ZipFileSystemTestSetup.firstProject
+ .getFolder(ZipFileSystemTestSetup.NESTED_ZIP_FILE_PARENT_NAME);
+ ensureExists(openedNestedZipFileParent);
+ IFile nestedZipFileChild = openedNestedZipFileParent.getFile(ZipFileSystemTestSetup.NESTED_ZIP_FILE_CHILD_NAME);
+ ensureExists(nestedZipFileChild);
+
+ // Attempt to open the nested ZIP file and expect an exception
+ try {
+ ZipFileSystemTestUtil.openZipFile(nestedZipFileChild);
+ fail("Expected a CoreException to be thrown when opening a nested ZIP file");
+ } catch (CoreException e) {
+ // Verify that the expected exception was thrown
+ assertTrue("Expected CoreException to be thrown when opening a nested ZIP file",
+ e.getMessage().contains("Nested ZIP files are not allowed to be opened"));
+
+ IFolder openedNestedZipFileChild = ZipFileSystemTestSetup.firstProject
+ .getFolder(ZipFileSystemTestSetup.NESTED_ZIP_FILE_CHILD_NAME);
+ ensureDoesNotExist(openedNestedZipFileChild);
+ }
+ }
+
+ @Test
+ public void testOpenDeepNestedTextFile() throws IOException, CoreException, URISyntaxException {
+ ZipFileSystemTestSetup.copyZipFileIntoProject(ZipFileSystemTestSetup.firstProject,
+ ZipFileSystemTestSetup.NESTED_ZIP_FILE_PARENT_NAME);
+ IFile nestedZipFileParent = ZipFileSystemTestSetup.firstProject
+ .getFile(ZipFileSystemTestSetup.NESTED_ZIP_FILE_PARENT_NAME);
+ ensureExists(nestedZipFileParent);
+ ZipFileSystemTestUtil.openZipFile(nestedZipFileParent);
+ IFolder openedNestedZipFileParent = ZipFileSystemTestSetup.firstProject
+ .getFolder(ZipFileSystemTestSetup.NESTED_ZIP_FILE_PARENT_NAME);
+ ensureExists(openedNestedZipFileParent);
+
+ String nestedPath = "sub1/Text.txt";
+ IFile nestedFile = openedNestedZipFileParent.getFile(nestedPath);
+ ensureExists(nestedFile);
+ assertTextFileContent(nestedFile, "Hello World!");
+
+ String deepNestedPath = "sub1/sub2/sub3/sub4/sub5/sub6/sub8/sub9/sub10/Text.txt";
+ IFile deepNestedFile = openedNestedZipFileParent.getFile(deepNestedPath);
+ ensureExists(deepNestedFile);
+ assertTextFileContent(deepNestedFile, "Hello World!");
+ }
+
+ @Test
+ public void testOpenFakeZip() {
+ try {
+ ZipFileSystemTestSetup.copyZipFileIntoProject(ZipFileSystemTestSetup.firstProject,
+ ZipFileSystemTestSetup.FAKE_ZIP_FILE_NAME);
+ IFile fakeZipFile = ZipFileSystemTestSetup.firstProject.getFile(ZipFileSystemTestSetup.FAKE_ZIP_FILE_NAME);
+ ensureExists(fakeZipFile);
+
+ ZipFileSystemTestUtil.openZipFile(fakeZipFile);
+ fail("Expected an IOException due to incorrect file header.");
+ } catch (CoreException e) {
+ String expectedMessage = "Failed to open ZIP file due to incorrect file header: "
+ + ZipFileSystemTestSetup.FAKE_ZIP_FILE_NAME;
+ assertTrue("Expected different error message", e.getMessage().contains(expectedMessage));
+ } catch (Exception e) {
+ fail("Expected a CoreException, but got a different type of exception.");
+ }
+ }
+
+ @Test
+ public void testOpenPasswordProtectedZip() {
+ try {
+ ZipFileSystemTestSetup.copyZipFileIntoProject(ZipFileSystemTestSetup.firstProject,
+ ZipFileSystemTestSetup.PASSWORD_PROTECTED_ZIP_FILE_NAME);
+ IFile passwordProtectedZipFile = ZipFileSystemTestSetup.firstProject
+ .getFile(ZipFileSystemTestSetup.PASSWORD_PROTECTED_ZIP_FILE_NAME);
+ ensureExists(passwordProtectedZipFile);
+
+ ZipFileSystemTestUtil.openZipFile(passwordProtectedZipFile);
+ fail("Expected an IOException due to password protection.");
+ } catch (CoreException e) {
+ String expectedMessage = "Zip File could not be opened";
+ assertTrue("Expected different error message", e.getMessage().contains(expectedMessage));
+ } catch (Exception e) {
+ fail("Expected a CoreException, but got a different type of exception.");
+ }
+ }
+}
diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/RenameTest.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/RenameTest.java
new file mode 100644
index 00000000000..7cf04161e8b
--- /dev/null
+++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/RenameTest.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Vector Informatik GmbH 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: Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.core.tests.filesystem.zip;
+
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.ensureDoesNotExist;
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.ensureExists;
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.getMonitor;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+public class RenameTest {
+
+ @BeforeEach
+ public void setup() throws Exception {
+ ZipFileSystemTestSetup.defaultSetup();
+ }
+
+ @AfterEach
+ public void teardown() throws Exception {
+ ZipFileSystemTestSetup.teardown();
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testRenameZipFile(String zipFileName) throws Exception {
+ // IFolder is renamed by moving with the new path
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName);
+ IFolder renamedOpenZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName + "Renamed");
+ openedZipFile.move(renamedOpenZipFile.getFullPath(), false, getMonitor());
+ ensureExists(renamedOpenZipFile);
+ ensureDoesNotExist(openedZipFile);
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testRenameFileInsideOfZipFile(String zipFileName) throws Exception {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName);
+ IFile textFile = openedZipFile.getFile(ZipFileSystemTestSetup.TEXT_FILE_NAME);
+ IFile renamedTextFile = openedZipFile.getFile(textFile.getName() + "Renamed");
+ textFile.move(renamedTextFile.getFullPath(), false, getMonitor());
+ ensureExists(renamedTextFile);
+ ensureDoesNotExist(textFile);
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testRenameFolderInsideOfZipFile(String zipFileName) throws Exception {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject.getFolder(zipFileName);
+ IFolder folder = openedZipFile.getFolder("newFolder");
+ ensureDoesNotExist(folder);
+ folder.create(false, true, getMonitor());
+ ensureExists(folder);
+ IFolder renamedFolder = openedZipFile.getFolder(folder.getName() + "Renamed");
+ folder.move(renamedFolder.getFullPath(), false, getMonitor());
+ ensureExists(renamedFolder);
+ ensureDoesNotExist(folder);
+ }
+}
diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/SetupTest.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/SetupTest.java
new file mode 100644
index 00000000000..e226cc6bd7f
--- /dev/null
+++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/SetupTest.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Vector Informatik GmbH 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: Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.core.tests.filesystem.zip;
+
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.assertTextFileContent;
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.ensureExists;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+public class SetupTest {
+
+ @BeforeEach
+ public void setup() throws Exception {
+ ZipFileSystemTestSetup.defaultSetup();
+ }
+
+ @AfterEach
+ public void teardown() throws Exception {
+ ZipFileSystemTestSetup.teardown();
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testZipFileInProject(String zipFileName) throws Exception {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject
+ .getFolder(zipFileName);
+ ensureExists(openedZipFile);
+ }
+
+ @ParameterizedTest
+ @MethodSource("org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil#zipFileNames")
+ public void testTextFileInZipFile(String zipFileName) throws Exception {
+ IFolder openedZipFile = ZipFileSystemTestSetup.firstProject
+ .getFolder(zipFileName);
+
+ IFile textFile = openedZipFile.getFile(ZipFileSystemTestSetup.TEXT_FILE_NAME);
+ ensureExists(textFile);
+ assertTextFileContent(textFile, "Hello World!");
+ }
+}
diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/ZipFileSystemTestSetup.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/ZipFileSystemTestSetup.java
new file mode 100644
index 00000000000..20fdc41b1d9
--- /dev/null
+++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/ZipFileSystemTestSetup.java
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Vector Informatik GmbH 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: Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.core.tests.filesystem.zip;
+
+import static org.eclipse.core.tests.filesystem.zip.ZipFileSystemTestUtil.ensureExists;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Platform;
+
+class ZipFileSystemTestSetup {
+
+ static final String FIRST_PROJECT_NAME = "TestProject";
+ static final String SECOND_PROJECT_NAME = "SecondProject";
+ static final String ZIP_FILE_VIRTUAL_FOLDER_NAME = "BasicText.zip"; // Assuming the ZIP is represented as this
+ // folder
+ static final String EMPTY_ZIP_FILE_NAME = "Empty.zip";
+ static final String NESTED_ZIP_FILE_PARENT_NAME = "NestedZipFileParent.zip";
+ static final String NESTED_ZIP_FILE_CHILD_NAME = "NestedZipFileChild.zip";
+ static final String TEXT_FILE_NAME = "Text.txt";
+ static final String DEEP_NESTED_ZIP_FILE_NAME = "DeepNested.zip";
+ static final String FAKE_ZIP_FILE_NAME = "Fake.zip";
+ static final String PASSWORD_PROTECTED_ZIP_FILE_NAME = "PasswordProtected.zip";
+ static IProject firstProject;
+ static IProject secondProject;
+ static IProgressMonitor progressMonitor = new NullProgressMonitor();
+
+ static void defaultSetup() throws Exception {
+ String[] defaultZipFileNames = { ZIP_FILE_VIRTUAL_FOLDER_NAME };
+ setup(defaultZipFileNames);
+ }
+
+ static void setup(String[] zipFileNames) throws Exception {
+ firstProject = createProject(FIRST_PROJECT_NAME);
+ refreshProject(firstProject);
+ for (String zipFileName : zipFileNames) {
+ copyZipFileIntoProject(firstProject, zipFileName);
+ refreshProject(firstProject);
+ ZipFileSystemTestUtil.openZipFile(firstProject.getFile(zipFileName));
+ }
+ }
+
+ static void setupWithTwoProjects() throws Exception {
+ defaultSetup();
+ secondProject = createProject(SECOND_PROJECT_NAME);
+ refreshProject(secondProject);
+ refreshEntireWorkspace();
+ }
+
+ static void teardown() throws Exception {
+ deleteProject(firstProject);
+ deleteProject(secondProject);
+ }
+
+ private static void deleteProject(IProject project) throws CoreException {
+ if (project != null && project.exists()) {
+ project.delete(true, true, progressMonitor);
+ project = null;
+ }
+ }
+
+ static IProject createProject(String projectName) throws CoreException {
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ IProject project = workspace.getRoot().getProject(projectName);
+
+ if (!project.exists()) {
+ project.create(progressMonitor);
+ }
+ project.open(progressMonitor);
+ return project;
+ }
+
+ private static void refreshProject(IProject project) {
+ try {
+ if (project.exists() && project.isOpen()) {
+ // Refreshing the specific project
+ project.refreshLocal(IResource.DEPTH_INFINITE, null);
+ }
+ } catch (CoreException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void refreshEntireWorkspace() {
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ try {
+ // IResource.DEPTH_INFINITE will cause all resources in the workspace to be
+ // refreshed.
+ workspace.getRoot().refreshLocal(IResource.DEPTH_INFINITE, null);
+ } catch (CoreException e) {
+ e.printStackTrace();
+ }
+ }
+
+ static void copyZipFileIntoProject(IProject project, String zipFileName) throws IOException, CoreException {
+ // Resolve the source file URL from the plugin bundle
+ URL zipFileUrl = Platform.getBundle("org.eclipse.core.tests.resources")
+ .getEntry("resources/ZipFileSystem/" + zipFileName);
+ // Ensure proper conversion from URL to URI to Path
+ URL resolvedURL = FileLocator.resolve(zipFileUrl); // Resolves any redirection or bundling
+ java.nio.file.Path sourcePath;
+ try {
+ // Convert URL to URI to Path correctly handling spaces and special characters
+ URI resolvedURI = resolvedURL.toURI();
+ sourcePath = Paths.get(resolvedURI);
+ } catch (URISyntaxException e) {
+ throw new IOException("Failed to resolve URI for the ZIP file", e);
+ }
+
+ // Determine the target location within the project
+ java.nio.file.Path targetPath = Paths.get(project.getLocation().toOSString(), zipFileName);
+
+ // Copy the file using java.nio.file.Files
+ Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
+
+ // Refresh the project to make Eclipse aware of the new file
+ project.refreshLocal(IResource.DEPTH_INFINITE, null);
+ }
+
+ static void copyAndOpenNestedZipFileIntoProject() throws IOException, CoreException, URISyntaxException {
+ copyZipFileIntoProject(firstProject, NESTED_ZIP_FILE_PARENT_NAME);
+ IFile nestedZipFileParent = firstProject.getFile(NESTED_ZIP_FILE_PARENT_NAME);
+ ensureExists(nestedZipFileParent);
+ ZipFileSystemTestUtil.openZipFile(nestedZipFileParent);
+ IFolder openedNestedZipFileParent = firstProject.getFolder(NESTED_ZIP_FILE_PARENT_NAME);
+ ensureExists(openedNestedZipFileParent);
+ IFile nestedZipFileChild = openedNestedZipFileParent.getFile(NESTED_ZIP_FILE_CHILD_NAME);
+ ensureExists(nestedZipFileChild);
+ ZipFileSystemTestUtil.openZipFile(nestedZipFileChild);
+ IFolder openedNestedZipFileChild = openedNestedZipFileParent
+ .getFolder(NESTED_ZIP_FILE_CHILD_NAME);
+ ensureExists(openedNestedZipFileChild);
+ }
+}
diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/ZipFileSystemTestUtil.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/ZipFileSystemTestUtil.java
new file mode 100644
index 00000000000..a8df732da80
--- /dev/null
+++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/filesystem/zip/ZipFileSystemTestUtil.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Vector Informatik GmbH 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: Vector Informatik GmbH - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.core.tests.filesystem.zip;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URISyntaxException;
+import java.util.stream.Stream;
+import org.eclipse.core.filesystem.EFS;
+import org.eclipse.core.filesystem.IFileInfo;
+import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ZipFileTransformer;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.tests.harness.FussyProgressMonitor;
+import org.junit.Assert;
+
+class ZipFileSystemTestUtil {
+
+ public static Stream zipFileNames() {
+ return Stream.of(ZipFileSystemTestSetup.ZIP_FILE_VIRTUAL_FOLDER_NAME);
+ }
+
+ static void ensureExists(IResource resource) throws CoreException, IOException {
+ switch (resource.getType()) {
+ case IResource.FILE: {
+ IFileStore fileStore = EFS.getStore(resource.getLocationURI());
+ ensureExistsInFileSystem(fileStore);
+ ensureExistsInWorkspace((IFile) resource);
+ break;
+ }
+ case IResource.FOLDER: {
+ IFileStore fileStore = EFS.getStore(resource.getLocationURI());
+ ensureExistsInFileSystem(fileStore);
+ ensureExistsInWorkspace((IFolder) resource);
+ break;
+ }
+ default:
+ throw new IllegalArgumentException("Unexpected value: " + resource.getType());
+ }
+ }
+
+ static void ensureDoesNotExist(IResource resource) throws CoreException, IOException {
+ switch (resource.getType()) {
+ case IResource.FILE: {
+ IFileStore fileStore = EFS.getStore(resource.getLocationURI());
+ ensureDoesNotExistInFileSystem(fileStore);
+ ensureDoesNotExistInWorkspace((IFile) resource);
+ break;
+ }
+ case IResource.FOLDER: {
+ IFileStore fileStore = EFS.getStore(resource.getLocationURI());
+ ensureDoesNotExistInFileSystem(fileStore);
+ ensureDoesNotExistInWorkspace((IFolder) resource);
+ break;
+ }
+ default:
+ throw new IllegalArgumentException("Unexpected value: " + resource.getType());
+ }
+ }
+
+ static void assertTextFileContent(IFile textFile, String expectedContent) throws IOException, CoreException {
+ try (InputStreamReader isr = new InputStreamReader(textFile.getContents());
+ BufferedReader reader = new BufferedReader(isr)) {
+ String content = reader.readLine(); // Assuming the file has a single line with "Hello World!"
+ Assert.assertEquals("The content of " + textFile.getName() + " should be '" + expectedContent + "'",
+ expectedContent, content);
+ }
+ }
+
+ private static void ensureDoesNotExistInFileSystem(IFileStore store) throws CoreException {
+ assertTrue("store was not properly deleted: " + store, !store.fetchInfo().exists());
+ }
+
+ private static void ensureExistsInFileSystem(IFileStore store) throws CoreException, IOException {
+ final IFileInfo info = store.fetchInfo();
+ assertTrue("file info for store does not exist: " + store, info.exists());
+ }
+
+ private static void ensureDoesNotExistInWorkspace(IFile file) throws CoreException {
+ assertTrue("file was not properly deleted: " + file, !file.exists());
+ }
+
+ private static void ensureDoesNotExistInWorkspace(IFolder folder) throws CoreException {
+ assertTrue("folder was not properly deleted: " + folder, !folder.exists());
+ }
+
+ private static void ensureExistsInWorkspace(IFile file) throws CoreException, IOException {
+ assertTrue("file does not exist in workspace: " + file, file.exists());
+ }
+
+ private static void ensureExistsInWorkspace(IFolder folder) throws CoreException, IOException {
+ assertTrue("folder does not exist in workspace: " + folder, folder.exists());
+ }
+
+ static IProgressMonitor getMonitor() {
+ return new FussyProgressMonitor();
+ }
+
+ static void openZipFile(IFile file) throws URISyntaxException, CoreException, IOException {
+ ZipFileTransformer.openZipFile(file, new NullProgressMonitor(), false);
+ }
+
+ static void openZipFileBackground(IFile file) throws URISyntaxException, CoreException, IOException {
+ ZipFileTransformer.openZipFile(file, new NullProgressMonitor(), true);
+ }
+
+ static void closeZipFile(IFolder folder) throws Exception {
+ ZipFileTransformer.closeZipFile(folder);
+ }
+
+ static void printContents(IContainer container, String indent) throws CoreException {
+ IResource[] members = container.members();
+ for (IResource member : members) {
+ if (member instanceof IFile) {
+ System.out.println(indent + "File: " + member.getName());
+ } else if (member instanceof IContainer) { // This can be IFolder or IProject
+ System.out.println(indent + "Folder: " + member.getName());
+ printContents((IContainer) member, indent + " "); // Recursively print contents
+ }
+ }
+ }
+
+}
diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/AutomatedResourceTests.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/AutomatedResourceTests.java
index 38d3f7545fe..3c899db1ab2 100644
--- a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/AutomatedResourceTests.java
+++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/AutomatedResourceTests.java
@@ -23,6 +23,7 @@
@Suite
@SelectClasses({ //
org.eclipse.core.tests.filesystem.AllFileSystemTests.class, //
+ org.eclipse.core.tests.filesystem.zip.AllZipFileSystemTests.class, //
org.eclipse.core.tests.internal.alias.AllAliasTests.class, //
org.eclipse.core.tests.internal.builders.AllBuilderTests.class, //
org.eclipse.core.tests.internal.dtree.AllDtreeTests.class, //