I am using java.util.Zip and java.util.ZipEntry to successfully extra a zip file's contents to disk. I would like to maintain the file permissions set when extracting on a *nix file-system.
Can anyone point me to the "correct" way to do this?
I am using java.util.Zip and java.util.ZipEntry to successfully extra a zip file's contents to disk. I would like to maintain the file permissions set when extracting on a *nix file-system.
Can anyone point me to the "correct" way to do this?
Essentially, you can't STORE (unix) file permissions in Zip/Jar files, so you can't preserve them when extracting your jar (they were lost when the jar was created to begin with). See this question: creating a jar file - preserving file permissions
If you need the file permissions preserved in the archive and restored when extracting, you need to consider the alternative .tar or .tar.gz / .tar.bz2 format, which is also natively supported by most Java build tools (Ant, Gradle, Maven...)
I think it is actually impossible to keep the permissions correctly.
Permissions are very OS specific: while POSIX file permissions allow the user to set whether you can read, write or execute a file for the file owner, the group and others, the NTFS file system has a similar system but the concept for an execute permission is inexistant. And the early FAT/FAT32 file syste, do not have file permissions at all (a part from the read-only attribute).
Being cross-platform, it would be difficult for java to set the permission properly on the newly created (unzipped) files depending on the underlying OS....
That said, Java 6 has a new java.io.File class that allows you to set permissions (with methods like setExecutable(), setReadable(), etc...)
These helped me a lot, especially the setExecutable() which was my main concerned when having to unzip executables on a Linux file system. And you don't have to bother about figuring out what OS you are running on as the method will simply do nothing if running under Windows or other systems without the concept of executable files.
The unix permissions are stored in the zip, either in the entry external attributes, or in the extra fields (using the "Asi" extra field, tagged with the 0x756E id). java.util.zip.ZipEntry
exposes the extra fields and the Asi field could be read if there is one, but the external attributes are not accessible. So it's not possible to restore the files permissions in all cases using only the JDK zip implementation.
Fortunately the Apache Commons Compress project has its own ZipFile implementation which parses the external attributes, the permissions are exposed with the ZipArchiveEntry.getUnixMode() method. Then with Ant's PermissionUtils class and the Java NIO API, the permissions can be applied back to the file extracted with:
Files.setPosixFilePermissions(path, PermissionUtils.permissionsFromMode(entry.getUnixMode()));
Look at Apache Commons Compress and look at TarArchiveEntry, that should preserve the file permissions like you want it to.
TarArchiveEntry entry = tarInput.getNextTarEntry();
Here are the javadocs. I think I've gone Commons mad...
As tracked in this OpenJDK bug: https://bugs.openjdk.java.net/browse/JDK-6194856:
The "standard" zip file format does not have any way to store "executable file" meta-information, since it was originally designed for MS-DOS filesystems.
In order to preserve Unix information like file modes, the zip handling code would have to handle extensions to the zip file format. Other zip implementations have such extensions.
There are some extensions to the file format that would allow maintaining this kind of information, but it can never be guaranteed (there is no requirement that zip files contain such "extended" metadata) and it would be a lot of work to implement and (especially!) test.
Also see this answer: Can i store unix permissions in a zip file (built with apache ant)?
Non-standard Java libraries may implement this (such as apache-commons).
Essentially, you can't STORE (unix) file permissions in Zip/Jar files, so you can't preserve them when extracting your jar (they were lost when the jar was created to begin with). See this question: creating a jar file - preserving file permissions
If you need the file permissions preserved in the archive and restored when extracting, you need to consider the alternative .tar or .tar.gz / .tar.bz2 format, which is also natively supported by most Java build tools (Ant, Gradle, Maven...)
I actually sat there looking over these answers and was stuck with this issue but then I realized I was doing something rather silly.
I was extracting to a temp folder, then using FileUtils.copyDirectory
to copy the files from the temp folder to the new folder.
Instead of doing a copy, I changed to a move operation. now it worked.
I can confirm, on Ubuntu Linux 22.04, this maintains file permissions.
Uses:
implementation group: 'org.rauschig', name: 'jarchivelib', version: '1.2.0'
import org.rauschig.jarchivelib.ArchiveFormat;
import org.rauschig.jarchivelib.Archiver;
import org.rauschig.jarchivelib.ArchiverFactory;
import org.rauschig.jarchivelib.CompressionType;
public static void unzip(File zipFile, File targetDirectory) throws IOException, IllegalAccessException {
Archiver archiver = ArchiverFactory.createArchiver(ArchiveFormat.ZIP);
archiver.extract(zipFile, targetDirectory);
}
public static void unTarGz(File tarFile, File targetDirectory) throws IOException {
Archiver archiver = ArchiverFactory.createArchiver(ArchiveFormat.TAR, CompressionType.GZIP);
archiver.extract(tarFile, targetDirectory);
}
If you use Apache Commons Compress , you can set the readonly flag using the external attributes.
The flag will be preserved after extraction in windows.
zipEntry.setVersionMadeBy(0x0000); // 00 is for MSDOS/Windows
zipEntry.setExternalAttributes(zipEntry.getExternalAttributes() | 0x00000001L); // First bit = 1 -> Readonly flag in windows
for more information please refer to the ZIP format spec. https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.3.9.TXT
© 2022 - 2024 — McMap. All rights reserved.