Use Apache Commons Compress instead of java.util.zip
When the SDK installer unarchives the zip files, it is important to keep the permissions for executable (Linux/MacOS) or the tools required to build applications (aapt, aidl, ...) won't work. Since java.util.zip does not provide support for permissions, we now use the Apache Commons Compress component that allows us to read the permission from the archive.
This commit is contained in:
@@ -127,6 +127,7 @@ framework/anttasks.jar tools/lib/anttasks.jar
|
|||||||
|
|
||||||
# sdkmanager
|
# sdkmanager
|
||||||
bin/android tools/android
|
bin/android tools/android
|
||||||
|
framework/commons-compress-1.0.jar tools/lib/commons-compress-1.0.jar
|
||||||
framework/sdklib.jar tools/lib/sdklib.jar
|
framework/sdklib.jar tools/lib/sdklib.jar
|
||||||
framework/sdkuilib.jar tools/lib/sdkuilib.jar
|
framework/sdkuilib.jar tools/lib/sdkuilib.jar
|
||||||
framework/sdkmanager.jar tools/lib/sdkmanager.jar
|
framework/sdkmanager.jar tools/lib/sdkmanager.jar
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<classpath>
|
<classpath>
|
||||||
<classpathentry kind="src" path="src"/>
|
<classpathentry kind="src" path="src"/>
|
||||||
<classpathentry kind="src" path="tests"/>
|
<classpathentry kind="src" path="tests"/>
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||||
<classpathentry combineaccessrules="false" kind="src" path="/AndroidPrefs"/>
|
<classpathentry combineaccessrules="false" kind="src" path="/AndroidPrefs"/>
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
|
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
|
||||||
<classpathentry kind="output" path="bin"/>
|
<classpathentry kind="var" path="ANDROID_SRC/prebuilt/common/commons-compress/commons-compress-1.0.jar"/>
|
||||||
</classpath>
|
<classpathentry kind="output" path="bin"/>
|
||||||
|
</classpath>
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files)
|
|||||||
LOCAL_JAVA_RESOURCE_DIRS := .
|
LOCAL_JAVA_RESOURCE_DIRS := .
|
||||||
|
|
||||||
LOCAL_JAVA_LIBRARIES := \
|
LOCAL_JAVA_LIBRARIES := \
|
||||||
androidprefs
|
androidprefs \
|
||||||
|
commons-compress-1.0
|
||||||
|
|
||||||
LOCAL_MODULE := sdklib
|
LOCAL_MODULE := sdklib
|
||||||
|
|
||||||
|
|||||||
@@ -16,19 +16,21 @@
|
|||||||
|
|
||||||
package com.android.sdklib.internal.repository;
|
package com.android.sdklib.internal.repository;
|
||||||
|
|
||||||
|
import com.android.sdklib.SdkConstants;
|
||||||
import com.android.sdklib.SdkManager;
|
import com.android.sdklib.SdkManager;
|
||||||
|
|
||||||
|
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
||||||
|
import org.apache.commons.compress.archivers.zip.ZipFile;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.Enumeration;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.zip.ZipEntry;
|
|
||||||
import java.util.zip.ZipInputStream;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -692,6 +694,7 @@ public class Archive implements IDescription {
|
|||||||
* unarchiving. However we return that root folder name to the caller, as it can be used
|
* unarchiving. However we return that root folder name to the caller, as it can be used
|
||||||
* as a template to know what destination directory to use in the Add-on case.
|
* as a template to know what destination directory to use in the Add-on case.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
private boolean unzipFolder(File archiveFile,
|
private boolean unzipFolder(File archiveFile,
|
||||||
long compressedSize,
|
long compressedSize,
|
||||||
File unzipDestFolder,
|
File unzipDestFolder,
|
||||||
@@ -701,11 +704,13 @@ public class Archive implements IDescription {
|
|||||||
|
|
||||||
description += " (%1$d%%)";
|
description += " (%1$d%%)";
|
||||||
|
|
||||||
FileInputStream fis = null;
|
ZipFile zipFile = null;
|
||||||
ZipInputStream zis = null;
|
|
||||||
try {
|
try {
|
||||||
fis = new FileInputStream(archiveFile);
|
zipFile = new ZipFile(archiveFile);
|
||||||
zis = new ZipInputStream(fis);
|
|
||||||
|
// figure if we'll need to set the unix permission
|
||||||
|
boolean usingUnixPerm = SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_DARWIN ||
|
||||||
|
SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_LINUX;
|
||||||
|
|
||||||
// To advance the percent and the progress bar, we don't know the number of
|
// To advance the percent and the progress bar, we don't know the number of
|
||||||
// items left to unzip. However we know the size of the archive and the size of
|
// items left to unzip. However we know the size of the archive and the size of
|
||||||
@@ -718,8 +723,10 @@ public class Archive implements IDescription {
|
|||||||
|
|
||||||
byte[] buf = new byte[65536];
|
byte[] buf = new byte[65536];
|
||||||
|
|
||||||
ZipEntry entry;
|
Enumeration<ZipArchiveEntry> entries =
|
||||||
while ((entry = zis.getNextEntry()) != null) {
|
(Enumeration<ZipArchiveEntry>)zipFile.getEntries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
ZipArchiveEntry entry = entries.nextElement();
|
||||||
|
|
||||||
String name = entry.getName();
|
String name = entry.getName();
|
||||||
|
|
||||||
@@ -768,7 +775,8 @@ public class Archive implements IDescription {
|
|||||||
try {
|
try {
|
||||||
fos = new FileOutputStream(destFile);
|
fos = new FileOutputStream(destFile);
|
||||||
int n;
|
int n;
|
||||||
while ((n = zis.read(buf)) != -1) {
|
InputStream entryContent = zipFile.getInputStream(entry);
|
||||||
|
while ((n = entryContent.read(buf)) != -1) {
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
fos.write(buf, 0, n);
|
fos.write(buf, 0, n);
|
||||||
}
|
}
|
||||||
@@ -779,6 +787,11 @@ public class Archive implements IDescription {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if needed set the permissions.
|
||||||
|
if (usingUnixPerm) {
|
||||||
|
setPermission(destFile, entry.getUnixMode());
|
||||||
|
}
|
||||||
|
|
||||||
// Increment progress bar to match. We update only between files.
|
// Increment progress bar to match. We update only between files.
|
||||||
for(incTotal += entry.getCompressedSize(); incCurr < incTotal; incCurr += incStep) {
|
for(incTotal += entry.getCompressedSize(); incCurr < incTotal; incCurr += incStep) {
|
||||||
monitor.incProgress(1);
|
monitor.incProgress(1);
|
||||||
@@ -801,16 +814,9 @@ public class Archive implements IDescription {
|
|||||||
monitor.setResult("Unzip failed: %1$s", e.getMessage());
|
monitor.setResult("Unzip failed: %1$s", e.getMessage());
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
if (zis != null) {
|
if (zipFile != null) {
|
||||||
try {
|
try {
|
||||||
zis.close();
|
zipFile.close();
|
||||||
} catch (IOException e) {
|
|
||||||
// pass
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (fis != null) {
|
|
||||||
try {
|
|
||||||
fis.close();
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// pass
|
// pass
|
||||||
}
|
}
|
||||||
@@ -902,5 +908,20 @@ public class Archive implements IDescription {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Unix permission on a file or folder.
|
||||||
|
* @param file The file to set permissions on.
|
||||||
|
* @param unixMode the permissions as received from {@link ZipArchiveEntry#getUnixMode()}.
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private void setPermission(File file, int unixMode) throws IOException {
|
||||||
|
// permissions contains more than user/group/all, and we need the 777 display mode, so we
|
||||||
|
// convert it in octal string and take the last 3 digits.
|
||||||
|
String permission = String.format("%o", unixMode);
|
||||||
|
permission = permission.substring(permission.length() - 3, permission.length());
|
||||||
|
|
||||||
|
Runtime.getRuntime().exec(new String[] {
|
||||||
|
"chmod", permission, file.getAbsolutePath()
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user