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, //