diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java index 9686cbd58..bd6b5bef2 100755 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/Archive.java @@ -16,8 +16,16 @@ package com.android.sdklib.internal.repository; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; /** @@ -32,6 +40,8 @@ import java.security.NoSuchAlgorithmException; */ public class Archive implements IDescription { + public static final int NUM_MONITOR_INC = 100; + /** The checksum type. */ public enum ChecksumType { /** A SHA1 checksum, represented as a 40-hex string. */ @@ -269,5 +279,450 @@ public class Archive implements IDescription { return true; } + + /** + * Install this {@link Archive}s. + * The archive will be skipped if it is incompatible. + * + * @return True if the archive was installed, false otherwise. + */ + public boolean install(String osSdkRoot, ITaskMonitor monitor) { + + File archiveFile = null; + try { + String name = getParentPackage().getShortDescription(); + + // TODO: we should not see this test fail if we had the filter UI above. + if (!isCompatible()) { + monitor.setResult("Skipping incompatible archive: %1$s", name); + return false; + } + + archiveFile = downloadFile(monitor); + if (archiveFile != null) { + if (unarchive(osSdkRoot, archiveFile, monitor)) { + monitor.setResult("Installed: %1$s", name); + return true; + } + } + + } finally { + // Delete the temp archive if it exists + deleteFileOrFolder(archiveFile); + } + + return false; + } + + /** + * Downloads an archive and returns the temp file with it. + * Caller is responsible with deleting the temp file when done. + */ + private File downloadFile(ITaskMonitor monitor) { + + File tmpFileToDelete = null; + try { + File tmpFile = File.createTempFile("sdkupload", ".bin"); //$NON-NLS-1$ //$NON-NLS-2$ + tmpFileToDelete = tmpFile; + + String name = getParentPackage().getShortDescription(); + String desc = String.format("Downloading %1$s", name); + monitor.setDescription(desc); + + String link = getUrl(); + if (!link.startsWith("http://") //$NON-NLS-1$ + && !link.startsWith("https://") //$NON-NLS-1$ + && !link.startsWith("ftp://")) { //$NON-NLS-1$ + // Make the URL absolute by prepending the source + Package pkg = getParentPackage(); + RepoSource src = pkg.getParentSource(); + if (src == null) { + monitor.setResult("Internal error: no source for archive %1$s", name); + return null; + } + + // take the URL to the repository.xml and remove the last component + // to get the base + String repoXml = src.getUrl(); + int pos = repoXml.lastIndexOf('/'); + String base = repoXml.substring(0, pos + 1); + + link = base + link; + } + + if (fetchUrl(tmpFile, link, desc, monitor)) { + // Fetching was successful, don't delete the temp file here! + tmpFileToDelete = null; + return tmpFile; + } + + } catch (IOException e) { + monitor.setResult(e.getMessage()); + + } finally { + deleteFileOrFolder(tmpFileToDelete); + } + + return null; + } + + /** + * Actually performs the download. + * Also computes the SHA1 of the file on the fly. + *

+ * Success is defined as downloading as many bytes as was expected and having the same + * SHA1 as expected. Returns true on success or false if any of those checks fail. + *

+ * Increments the monitor by {@link #NUM_MONITOR_INC}. + */ + private boolean fetchUrl(File tmpFile, + String urlString, + String description, + ITaskMonitor monitor) { + URL url; + + description += " (%1$d%%, %2$.0f KiB/s, %3$d %4$s left)"; + + FileOutputStream os = null; + InputStream is = null; + try { + url = new URL(urlString); + is = url.openStream(); + os = new FileOutputStream(tmpFile); + + MessageDigest digester = getChecksumType().getMessageDigest(); + + byte[] buf = new byte[65536]; + int n; + + long total = 0; + long size = getSize(); + long inc = size / NUM_MONITOR_INC; + long next_inc = inc; + + long startMs = System.currentTimeMillis(); + long nextMs = startMs + 2000; // start update after 2 seconds + + while ((n = is.read(buf)) >= 0) { + if (n > 0) { + os.write(buf, 0, n); + digester.update(buf, 0, n); + } + + long timeMs = System.currentTimeMillis(); + + total += n; + if (total >= next_inc) { + monitor.incProgress(1); + next_inc += inc; + } + + if (timeMs > nextMs) { + long delta = timeMs - startMs; + if (total > 0 && delta > 0) { + // percent left to download + int percent = (int) (100 * total / size); + // speed in KiB/s + float speed = (float)total / (float)delta * (1000.f / 1024.f); + // time left to download the rest at the current KiB/s rate + int timeLeft = (speed > 1e-3) ? + (int)(((size - total) / 1024.0f) / speed) : + 0; + String timeUnit = "seconds"; + if (timeLeft > 120) { + timeUnit = "minutes"; + timeLeft /= 60; + } + + monitor.setDescription(description, percent, speed, timeLeft, timeUnit); + } + nextMs = timeMs + 1000; // update every second + } + + if (monitor.isCancelRequested()) { + monitor.setResult("Download aborted by user at %1$d bytes.", total); + return false; + } + + } + + if (total != size) { + monitor.setResult("Download finished with wrong size. Expected %1$d bytes, got %2$d bytes.", + size, total); + return false; + } + + // Create an hex string from the digest + byte[] digest = digester.digest(); + n = digest.length; + String hex = "0123456789abcdef"; //$NON-NLS-1$ + char[] hexDigest = new char[n * 2]; + for (int i = 0; i < n; i++) { + int b = digest[i] & 0x0FF; + hexDigest[i*2 + 0] = hex.charAt(b >>> 4); + hexDigest[i*2 + 1] = hex.charAt(b & 0x0f); + } + + String expected = getChecksum(); + String actual = new String(hexDigest); + if (!actual.equalsIgnoreCase(expected)) { + monitor.setResult("Download finished with wrong checksum. Expected %1$s, got %2$s.", + expected, actual); + return false; + } + + return true; + + } catch (Exception e) { + monitor.setResult(e.getMessage()); + + } finally { + if (os != null) { + try { + os.close(); + } catch (IOException e) { + // pass + } + } + + if (is != null) { + try { + is.close(); + } catch (IOException e) { + // pass + } + } + } + + return false; + } + + /** + * Install the given archive in the given folder. + */ + private boolean unarchive(String osSdkRoot, File archiveFile, ITaskMonitor monitor) { + String name = getParentPackage().getShortDescription(); + String desc = String.format("Installing %1$s", name); + monitor.setDescription(desc); + + File destFolder = getParentPackage().getInstallFolder(osSdkRoot); + + File unzipDestFolder = destFolder; + File renamedDestFolder = null; + + try { + // If this folder already exists, unzip in a temporary folder and then move/unlink. + if (destFolder.exists()) { + // Find a new temp folder that doesn't exist yet + unzipDestFolder = findTempFolder(destFolder, "new"); //$NON-NLS-1$ + + if (unzipDestFolder == null) { + // this should not seriously happen. + monitor.setResult("Failed to find a suitable temp directory similar to %1$s.", + destFolder.getPath()); + return false; + } + + if (!unzipDestFolder.mkdirs()) { + monitor.setResult("Failed to create temp directory %1$s", + unzipDestFolder.getPath()); + return false; + } + } + + if (!unzipFolder(archiveFile, getSize(), unzipDestFolder, desc, monitor)) { + return false; + } + + if (unzipDestFolder != destFolder) { + // Swap the old folder by the new one. + // Both original folders will be deleted in the finally clause below. + renamedDestFolder = findTempFolder(destFolder, "old"); //$NON-NLS-1$ + if (renamedDestFolder == null) { + // this should not seriously happen. + monitor.setResult("Failed to find a suitable temp directory similar to %1$s.", + destFolder.getPath()); + return false; + } + + if (!destFolder.renameTo(renamedDestFolder)) { + monitor.setResult("Failed to rename directory %1$s to %2$s", + destFolder.getPath(), renamedDestFolder.getPath()); + return false; + + } + if (!unzipDestFolder.renameTo(destFolder)) { + monitor.setResult("Failed to rename directory %1$s to %2$s", + unzipDestFolder.getPath(), destFolder.getPath()); + return false; + } + } + + return true; + + } finally { + // Cleanup if the unzip folder is still set. + deleteFileOrFolder(renamedDestFolder); + if (unzipDestFolder != destFolder) { + deleteFileOrFolder(unzipDestFolder); + } + } + } + + private boolean unzipFolder(File archiveFile, + long compressedSize, + File unzipDestFolder, + String description, + ITaskMonitor monitor) { + + description += " (%1$d%%)"; + + FileInputStream fis = null; + ZipInputStream zis = null; + try { + fis = new FileInputStream(archiveFile); + zis = new ZipInputStream(fis); + + // 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 + // each uncompressed item. The zip file format overhead is negligible so that's + // a good approximation. + long incStep = compressedSize / NUM_MONITOR_INC; + long incTotal = 0; + long incCurr = 0; + int lastPercent = 0; + + byte[] buf = new byte[65536]; + + ZipEntry entry; + while ((entry = zis.getNextEntry()) != null) { + + String name = entry.getName(); + + // ZipFile entries should have forward slashes, but not all Zip + // implementations can be expected to do that. + name = name.replace('\\', '/'); + + File destFile = new File(unzipDestFolder, name); + + if (name.endsWith("/")) { //$NON-NLS-1$ + // Create directory if it doesn't exist yet. This allows us to create + // empty directories. + if (!destFile.isDirectory() && !destFile.mkdirs()) { + monitor.setResult("Failed to create temp directory %1$s", + destFile.getPath()); + return false; + } + continue; + } else if (name.indexOf('/') != -1) { + // Otherwise it's a file in a sub-directory. + // Make sure the parent directory has been created. + File parentDir = destFile.getParentFile(); + if (!parentDir.isDirectory()) { + if (!parentDir.mkdirs()) { + monitor.setResult("Failed to create temp directory %1$s", + parentDir.getPath()); + return false; + } + } + } + + FileOutputStream fos = null; + try { + fos = new FileOutputStream(destFile); + int n; + while ((n = zis.read(buf)) != -1) { + if (n > 0) { + fos.write(buf, 0, n); + } + } + } finally { + if (fos != null) { + fos.close(); + } + } + + // Increment progress bar to match. We update only between files. + for(incTotal += entry.getCompressedSize(); incCurr < incTotal; incCurr += incStep) { + monitor.incProgress(1); + } + + int percent = (int) (100 * incTotal / compressedSize); + if (percent != lastPercent) { + monitor.setDescription(description, percent); + lastPercent = percent; + } + + if (monitor.isCancelRequested()) { + return false; + } + } + + return true; + + } catch (IOException e) { + monitor.setResult("Unzip failed: %1$s", e.getMessage()); + + } finally { + if (zis != null) { + try { + zis.close(); + } catch (IOException e) { + // pass + } + } + if (fis != null) { + try { + fis.close(); + } catch (IOException e) { + // pass + } + } + } + + return false; + } + + /** + * Finds a temp folder which name is similar to the one of the ideal folder + * and with a ".tmpN" appended. + *

+ * This operation is not atomic so there's no guarantee the folder can't get + * created in between. This is however unlikely and the caller can assume the + * returned folder does not exist yet. + *

+ * Returns null if no such folder can be found (e.g. if all candidates exist), + * which is rather unlikely. + */ + private File findTempFolder(File idealFolder, String suffix) { + String basePath = idealFolder.getPath(); + + for (int i = 1; i < 100; i++) { + File folder = new File(String.format("%1$s.%2$s%3$02d", basePath, suffix, i)); //$NON-NLS-1$ + if (!folder.exists()) { + return folder; + } + } + return null; + } + + /** + * Deletes a file or a directory. + * Directories are deleted recursively. + * The argument can be null. + */ + private void deleteFileOrFolder(File fileOrFolder) { + if (fileOrFolder != null) { + if (fileOrFolder.isDirectory()) { + // Must delete content recursively first + for (File item : fileOrFolder.listFiles()) { + deleteFileOrFolder(item); + } + } + if (!fileOrFolder.delete()) { + fileOrFolder.deleteOnExit(); + } + } + } } diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java index ddf53f04a..ead8d6175 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/UpdaterWindowImpl.java @@ -21,7 +21,6 @@ import com.android.sdklib.ISdkLog; import com.android.sdklib.internal.repository.Archive; import com.android.sdklib.internal.repository.ITask; import com.android.sdklib.internal.repository.ITaskMonitor; -import com.android.sdklib.internal.repository.Package; import com.android.sdklib.internal.repository.RepoSource; import com.android.sdklib.repository.SdkRepository; @@ -42,26 +41,16 @@ import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.List; import org.eclipse.swt.widgets.Shell; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Constructor; -import java.net.URL; -import java.security.MessageDigest; import java.util.ArrayList; import java.util.Collection; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; /** * This is the private implementation of the UpdateWindow. */ public class UpdaterWindowImpl { - private static final int NUM_MONITOR_INC = 100; - /** Internal data shared between the window and its pages. */ private final UpdaterData mUpdaterData = new UpdaterData(); /** The array of pages instances. Only one is visible at a time. */ @@ -351,7 +340,7 @@ public class UpdaterWindowImpl { mTaskFactory.start("Installing Archives", new ITask() { public void run(ITaskMonitor monitor) { - final int progressPerArchive = 2 * NUM_MONITOR_INC + 10; + final int progressPerArchive = 2 * Archive.NUM_MONITOR_INC; monitor.setProgressMax(archives.size() * progressPerArchive); monitor.setDescription("Preparing to install archives"); @@ -359,34 +348,20 @@ public class UpdaterWindowImpl { for (Archive archive : archives) { int nextProgress = monitor.getProgress() + progressPerArchive; - File archiveFile = null; try { if (monitor.isCancelRequested()) { break; } - String name = archive.getParentPackage().getShortDescription(); - - // TODO: we should not see this test fail if we had the filter UI above. - if (!archive.isCompatible()) { - monitor.setResult("Skipping incompatible archive: %1$s", name); - continue; + if (archive.install(mUpdaterData.getOsSdkRoot(), monitor)) { + numInstalled++; } - archiveFile = downloadArchive(archive, monitor); - if (archiveFile != null) { - if (installArchive(archive, archiveFile, monitor)) { - monitor.setResult("Installed: %1$s", name); - numInstalled++; - } - } } catch (Throwable t) { // Display anything unexpected in the monitor. monitor.setResult("Unexpected Error: %1$s", t.getMessage()); } finally { - // Delete the temp archive if it exists - deleteFileOrFolder(archiveFile); // Always move the progress bar to the desired position. // This allows internal methods to not have to care in case @@ -406,417 +381,6 @@ public class UpdaterWindowImpl { }); } - /** - * Downloads an archive and returns the temp file with it. - * Caller is responsible with deleting the temp file when done. - */ - private File downloadArchive(Archive archive, ITaskMonitor monitor) { - - File tmpFileToDelete = null; - try { - File tmpFile = File.createTempFile("sdkupload", ".bin"); //$NON-NLS-1$ //$NON-NLS-2$ - tmpFileToDelete = tmpFile; - - String name = archive.getParentPackage().getShortDescription(); - String desc = String.format("Downloading %1$s", name); - monitor.setDescription(desc); - - String link = archive.getUrl(); - if (!link.startsWith("http://") //$NON-NLS-1$ - && !link.startsWith("https://") //$NON-NLS-1$ - && !link.startsWith("ftp://")) { //$NON-NLS-1$ - // Make the URL absolute by prepending the source - Package pkg = archive.getParentPackage(); - RepoSource src = pkg.getParentSource(); - if (src == null) { - monitor.setResult("Internal error: no source for archive %1$s", name); - return null; - } - - // take the URL to the repository.xml and remove the last component - // to get the base - String repoXml = src.getUrl(); - int pos = repoXml.lastIndexOf('/'); - String base = repoXml.substring(0, pos + 1); - - link = base + link; - } - - if (fetchUrl(tmpFile, archive, link, desc, monitor)) { - // Fetching was successful, don't delete the temp file here! - tmpFileToDelete = null; - return tmpFile; - } - - } catch (IOException e) { - monitor.setResult(e.getMessage()); - - } finally { - deleteFileOrFolder(tmpFileToDelete); - } - return null; - } - - /** - * Actually performs the download. - * Also computes the SHA1 of the file on the fly. - *

- * Success is defined as downloading as many bytes as was expected and having the same - * SHA1 as expected. Returns true on success or false if any of those checks fail. - *

- * Increments the monitor by {@link #NUM_MONITOR_INC}. - */ - private boolean fetchUrl(File tmpFile, - Archive archive, - String urlString, - String description, - ITaskMonitor monitor) { - URL url; - - description += " (%1$d%%, %2$.0f KiB/s, %3$d %4$s left)"; - - FileOutputStream os = null; - InputStream is = null; - try { - url = new URL(urlString); - is = url.openStream(); - os = new FileOutputStream(tmpFile); - - MessageDigest digester = archive.getChecksumType().getMessageDigest(); - - byte[] buf = new byte[65536]; - int n; - - long total = 0; - long size = archive.getSize(); - long inc = size / NUM_MONITOR_INC; - long next_inc = inc; - - long startMs = System.currentTimeMillis(); - long nextMs = startMs + 2000; // start update after 2 seconds - - while ((n = is.read(buf)) >= 0) { - if (n > 0) { - os.write(buf, 0, n); - digester.update(buf, 0, n); - } - - long timeMs = System.currentTimeMillis(); - - total += n; - if (total >= next_inc) { - monitor.incProgress(1); - next_inc += inc; - } - - if (timeMs > nextMs) { - long delta = timeMs - startMs; - if (total > 0 && delta > 0) { - // percent left to download - int percent = (int) (100 * total / size); - // speed in KiB/s - float speed = (float)total / (float)delta * (1000.f / 1024.f); - // time left to download the rest at the current KiB/s rate - int timeLeft = (speed > 1e-3) ? - (int)(((size - total) / 1024.0f) / speed) : - 0; - String timeUnit = "seconds"; - if (timeLeft > 120) { - timeUnit = "minutes"; - timeLeft /= 60; - } - - monitor.setDescription(description, percent, speed, timeLeft, timeUnit); - } - nextMs = timeMs + 1000; // update every second - } - - if (monitor.isCancelRequested()) { - monitor.setResult("Download aborted by user at %1$d bytes.", total); - return false; - } - - } - - if (total != size) { - monitor.setResult("Download finished with wrong size. Expected %1$d bytes, got %2$d bytes.", - size, total); - return false; - } - - // Create an hex string from the digest - byte[] digest = digester.digest(); - n = digest.length; - String hex = "0123456789abcdef"; //$NON-NLS-1$ - char[] hexDigest = new char[n * 2]; - for (int i = 0; i < n; i++) { - int b = digest[i] & 0x0FF; - hexDigest[i*2 + 0] = hex.charAt(b >>> 4); - hexDigest[i*2 + 1] = hex.charAt(b & 0x0f); - } - - String expected = archive.getChecksum(); - String actual = new String(hexDigest); - if (!actual.equalsIgnoreCase(expected)) { - monitor.setResult("Download finished with wrong checksum. Expected %1$s, got %2$s.", - expected, actual); - return false; - } - - return true; - - } catch (Exception e) { - monitor.setResult(e.getMessage()); - - } finally { - if (os != null) { - try { - os.close(); - } catch (IOException e) { - // pass - } - } - - if (is != null) { - try { - is.close(); - } catch (IOException e) { - // pass - } - } - } - - return false; - } - - /** - * Install the given archive in the given folder. - */ - private boolean installArchive(Archive archive, File archiveFile, ITaskMonitor monitor) { - String name = archive.getParentPackage().getShortDescription(); - String desc = String.format("Installing %1$s", name); - monitor.setDescription(desc); - - File destFolder = archive.getParentPackage().getInstallFolder(mUpdaterData.getOsSdkRoot()); - - File unzipDestFolder = destFolder; - File renamedDestFolder = null; - - try { - // If this folder already exists, unzip in a temporary folder and then move/unlink. - if (destFolder.exists()) { - // Find a new temp folder that doesn't exist yet - unzipDestFolder = findTempFolder(destFolder, "new"); //$NON-NLS-1$ - - if (unzipDestFolder == null) { - // this should not seriously happen. - monitor.setResult("Failed to find a suitable temp directory similar to %1$s.", - destFolder.getPath()); - return false; - } - - if (!unzipDestFolder.mkdirs()) { - monitor.setResult("Failed to create temp directory %1$s", - unzipDestFolder.getPath()); - return false; - } - } - - if (!unzipFolder(archiveFile, archive.getSize(), unzipDestFolder, desc, monitor)) { - return false; - } - - if (unzipDestFolder != destFolder) { - // Swap the old folder by the new one. - // Both original folders will be deleted in the finally clause below. - renamedDestFolder = findTempFolder(destFolder, "old"); //$NON-NLS-1$ - if (renamedDestFolder == null) { - // this should not seriously happen. - monitor.setResult("Failed to find a suitable temp directory similar to %1$s.", - destFolder.getPath()); - return false; - } - - if (!destFolder.renameTo(renamedDestFolder)) { - monitor.setResult("Failed to rename directory %1$s to %2$s", - destFolder.getPath(), renamedDestFolder.getPath()); - return false; - - } - if (!unzipDestFolder.renameTo(destFolder)) { - monitor.setResult("Failed to rename directory %1$s to %2$s", - unzipDestFolder.getPath(), destFolder.getPath()); - return false; - } - } - - return true; - - } finally { - // Cleanup if the unzip folder is still set. - deleteFileOrFolder(renamedDestFolder); - if (unzipDestFolder != destFolder) { - deleteFileOrFolder(unzipDestFolder); - } - } - } - - private boolean unzipFolder(File archiveFile, - long compressedSize, - File unzipDestFolder, - String description, - ITaskMonitor monitor) { - - description += " (%1$d%%)"; - - FileInputStream fis = null; - ZipInputStream zis = null; - try { - fis = new FileInputStream(archiveFile); - zis = new ZipInputStream(fis); - - // 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 - // each uncompressed item. The zip file format overhead is negligible so that's - // a good approximation. - long incStep = compressedSize / NUM_MONITOR_INC; - long incTotal = 0; - long incCurr = 0; - int lastPercent = 0; - - byte[] buf = new byte[65536]; - - ZipEntry entry; - while ((entry = zis.getNextEntry()) != null) { - - String name = entry.getName(); - - // ZipFile entries should have forward slashes, but not all Zip - // implementations can be expected to do that. - name = name.replace('\\', '/'); - - File destFile = new File(unzipDestFolder, name); - - if (name.endsWith("/")) { //$NON-NLS-1$ - // Create directory if it doesn't exist yet. This allows us to create - // empty directories. - if (!destFile.isDirectory() && !destFile.mkdirs()) { - monitor.setResult("Failed to create temp directory %1$s", - destFile.getPath()); - return false; - } - continue; - } else if (name.indexOf('/') != -1) { - // Otherwise it's a file in a sub-directory. - // Make sure the parent directory has been created. - File parentDir = destFile.getParentFile(); - if (!parentDir.isDirectory()) { - if (!parentDir.mkdirs()) { - monitor.setResult("Failed to create temp directory %1$s", - parentDir.getPath()); - return false; - } - } - } - - FileOutputStream fos = null; - try { - fos = new FileOutputStream(destFile); - int n; - while ((n = zis.read(buf)) != -1) { - if (n > 0) { - fos.write(buf, 0, n); - } - } - } finally { - if (fos != null) { - fos.close(); - } - } - - // Increment progress bar to match. We update only between files. - for(incTotal += entry.getCompressedSize(); incCurr < incTotal; incCurr += incStep) { - monitor.incProgress(1); - } - - int percent = (int) (100 * incTotal / compressedSize); - if (percent != lastPercent) { - monitor.setDescription(description, percent); - lastPercent = percent; - } - - if (monitor.isCancelRequested()) { - return false; - } - } - - return true; - - } catch (IOException e) { - monitor.setResult("Unzip failed: %1$s", e.getMessage()); - - } finally { - if (zis != null) { - try { - zis.close(); - } catch (IOException e) { - // pass - } - } - if (fis != null) { - try { - fis.close(); - } catch (IOException e) { - // pass - } - } - } - - return false; - } - - /** - * Finds a temp folder which name is similar to the one of the ideal folder - * and with a ".tmpN" appended. - *

- * This operation is not atomic so there's no guarantee the folder can't get - * created in between. This is however unlikely and the caller can assume the - * returned folder does not exist yet. - *

- * Returns null if no such folder can be found (e.g. if all candidates exist), - * which is rather unlikely. - */ - private File findTempFolder(File idealFolder, String suffix) { - String basePath = idealFolder.getPath(); - - for (int i = 1; i < 100; i++) { - File folder = new File(String.format("%1$s.%2$s%3$02d", basePath, suffix, i)); //$NON-NLS-1$ - if (!folder.exists()) { - return folder; - } - } - return null; - } - - /** - * Deletes a file or a directory. - * Directories are deleted recursively. - * The argument can be null. - */ - private void deleteFileOrFolder(File fileOrFolder) { - if (fileOrFolder != null) { - if (fileOrFolder.isDirectory()) { - // Must delete content recursively first - for (File item : fileOrFolder.listFiles()) { - deleteFileOrFolder(item); - } - } - if (!fileOrFolder.delete()) { - fileOrFolder.deleteOnExit(); - } - } - } - // End of hiding from SWT Designer //$hide<<$ }