/* * Copyright 2010-2012, CloudBees Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.cloudbees.upload; import com.cloudbees.utils.ZipHelper; import com.thoughtworks.xstream.XStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; /** */ public final class ArchiveUtils { public static int ENTRY_DELETED = 1; public static int ENTRY_UPDATED = 2; public static int ENTRY_ADDED = 3; private static final String META_INF = "META-INF"; private static final String DELTA_FILE = "CB-DELTA.xml"; private ArchiveUtils() { throw new IllegalAccessError("Utility class"); } public static File createDeltaWarFile(Map<String, Long> existingArchiveCheckSums, File warFile, String tmp) throws IOException { Map<String, Integer> deltas = getDeltas(warFile.getAbsolutePath(), existingArchiveCheckSums); String tmpDir = makeTmpDir(warFile, tmp); ZipFile zipFile = new ZipFile(warFile.getAbsolutePath()); Enumeration<? extends ZipEntry> e = zipFile.entries(); while (e.hasMoreElements()) { ZipEntry entry = e.nextElement(); Integer delta = deltas.get(entry.getName()); if (delta != null && delta.intValue() != ArchiveUtils.ENTRY_DELETED) { // Copy the entry to tmp directory unArchiveZipEntry(tmpDir, zipFile, entry); } } // Add a file to the archive with the deltas File metaInfDir = new File(tmpDir + META_INF); metaInfDir.mkdirs(); File deltaFile = new File(metaInfDir, DELTA_FILE); XStream xstream = new XStream(); FileOutputStream fos = new FileOutputStream(deltaFile); xstream.toXML(deltas, fos); fos.close(); // Archive the deltas String deltaDir = warFile.getParent() == null ? "." : warFile.getParent(); String deltaArchiveFile = deltaDir + "/DELTA-" + warFile.getName(); archiveDirectory(tmpDir, deltaArchiveFile); deleteAll(new File(tmpDir)); return new File(deltaArchiveFile); } public static Map<String, Integer> getDeltas(String archiveFile, Map<String, Long> oldCheckSums) throws IOException { Map<String, Integer> deltas = new HashMap<String, Integer>(); Map<String, Long> newCheckSums = getCheckSums(archiveFile); ConcurrentHashMap<String, Long> checkSumsTmp = new ConcurrentHashMap<String, Long>(oldCheckSums); for (Map.Entry<String, Long> entry : newCheckSums.entrySet()) { String key = entry.getKey(); if (checkSumsTmp.get(key) == null) { deltas.put(key, ENTRY_ADDED); } else if (entry.getValue().longValue() != checkSumsTmp.get(key).longValue()) { deltas.put(key, ENTRY_UPDATED); checkSumsTmp.remove(key); } else { checkSumsTmp.remove(key); } } for (String key : checkSumsTmp.keySet()) { deltas.put(key, ENTRY_DELETED); } return deltas; } public static Map<String, Long> getCheckSums(String archiveFile) throws IOException { Map<String, Long> checkSums = new HashMap<String, Long>(); ZipFile zipFile = new ZipFile(archiveFile); Enumeration<? extends ZipEntry> e = zipFile.entries(); while (e.hasMoreElements()) { ZipEntry entry = e.nextElement(); checkSums.put(entry.getName(), entry.getCrc()); } return checkSums; } private static void unArchiveZipEntry(String destinationDirectory, ZipFile zipfile, ZipEntry entry) throws IOException { File file = ZipHelper.unzipEntryToFolder(entry, zipfile.getInputStream(entry), new File(destinationDirectory)); if (entry.getTime() > -1) { file.setLastModified(entry.getTime()); } } private static void archiveDirectory(String directory, String archiveFile) throws IOException { File archive = new File(archiveFile); archive.createNewFile(); FileOutputStream fileOutputStream = new FileOutputStream(archive); ZipOutputStream zipOutputStream = new ZipOutputStream(new BufferedOutputStream(fileOutputStream)); ZipHelper.addDirectoryToZip(new File(directory), new File(directory), null, zipOutputStream); zipOutputStream.close(); } private static String makeTmpDir(File file, String tmp) { if (tmp == null) { tmp = "."; } String fileName = file.getName(); int idx = fileName.lastIndexOf('.'); if (idx > -1) { fileName = fileName.substring(0, idx); } if (!tmp.endsWith(File.separator)) { tmp += File.separator; } tmp = tmp + "tmp" + fileName + File.separator; File dir = new File(tmp); deleteAll(dir); dir.mkdirs(); return tmp; } private static void deleteAll(File dir) { if (dir.exists()) { if (dir.isDirectory()) { File[] files = dir.listFiles(); if (files != null) { for (File f : files) { if (f.isDirectory()) { deleteAll(f); } else { f.delete(); } } } } dir.delete(); } } }