- /*
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2001-2002 The Apache Software Foundation. All rights
- * reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The end-user documentation included with the redistribution, if
- * any, must include the following acknowlegement:
- * "This product includes software developed by the
- * Apache Software Foundation (http://www.apache.org/)."
- * Alternately, this acknowlegement may appear in the software itself,
- * if and wherever such third-party acknowlegements normally appear.
- *
- * 4. The names "The Jakarta Project", "Ant", and "Apache Software
- * Foundation" must not be used to endorse or promote products derived
- * from this software without prior written permission. For written
- * permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache"
- * nor may "Apache" appear in their names without prior written
- * permission of the Apache Group.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- */
- package org.apache.tools.ant.taskdefs;
-
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.InputStreamReader;
- import java.io.IOException;
- import java.security.DigestInputStream;
- import java.security.MessageDigest;
- import java.security.NoSuchAlgorithmException;
- import java.security.NoSuchProviderException;
- import java.util.Enumeration;
- import java.util.Hashtable;
- import java.util.Vector;
- import org.apache.tools.ant.BuildException;
- import org.apache.tools.ant.DirectoryScanner;
- import org.apache.tools.ant.Project;
- import org.apache.tools.ant.taskdefs.condition.Condition;
- import org.apache.tools.ant.taskdefs.MatchingTask;
- import org.apache.tools.ant.types.FileSet;
-
- /**
- * This task can be used to create checksums for files.
- * It can also be used to verify checksums.
- *
- * @author <a href="mailto:umagesh@apache.org">Magesh Umasankar</a>
- *
- * @ant.task category="control"
- */
- public class Checksum extends MatchingTask implements Condition {
- /**
- * File for which checksum is to be calculated.
- */
- private File file = null;
- /**
- * MessageDigest algorithm to be used.
- */
- private String algorithm = "MD5";
- /**
- * MessageDigest Algorithm provider
- */
- private String provider = null;
- /**
- * File Extension that is be to used to create or identify
- * destination file
- */
- private String fileext;
- /**
- * Holds generated checksum and gets set as a Project Property.
- */
- private String property;
- /**
- * Whether or not to create a new file.
- * Defaults to <code>false</code>.
- */
- private boolean forceOverwrite;
- /**
- * Contains the result of a checksum verification. ("true" or "false")
- */
- private String verifyProperty;
- /**
- * Vector to hold source file sets.
- */
- private Vector filesets = new Vector();
- /**
- * Stores SourceFile, DestFile pairs and SourceFile, Property String pairs.
- */
- private Hashtable includeFileMap = new Hashtable();
- /**
- * Message Digest instance
- */
- private MessageDigest messageDigest;
- /**
- * is this task being used as a nested condition element?
- */
- private boolean isCondition;
-
- /**
- * Sets the file for which the checksum is to be calculated.
- */
- public void setFile(File file) {
- this.file = file;
- }
-
- /**
- * Sets the MessageDigest algorithm to be used
- * to calculate the checksum.
- */
- public void setAlgorithm(String algorithm) {
- this.algorithm = algorithm;
- }
-
- /**
- * Sets the MessageDigest algorithm provider to be used
- * to calculate the checksum.
- */
- public void setProvider(String provider) {
- this.provider = provider;
- }
-
- /**
- * Sets the File Extension that is be to used to
- * create or identify destination file
- */
- public void setFileext(String fileext) {
- this.fileext = fileext;
- }
-
- /**
- * Sets the property to hold the generated checksum
- */
- public void setProperty(String property) {
- this.property = property;
- }
-
- /**
- * Sets verify property. This project property holds
- * the result of a checksum verification - "true" or "false"
- */
- public void setVerifyproperty(String verifyProperty) {
- this.verifyProperty = verifyProperty;
- }
-
- /**
- * Whether or not to overwrite existing file irrespective of
- * whether it is newer than
- * the source file. Defaults to false.
- */
- public void setForceOverwrite(boolean forceOverwrite) {
- this.forceOverwrite = forceOverwrite;
- }
-
- /**
- * Adds a set of files (nested fileset attribute).
- */
- public void addFileset(FileSet set) {
- filesets.addElement(set);
- }
-
- /**
- * Calculate the checksum(s).
- */
- public void execute() throws BuildException {
- boolean value = validateAndExecute();
- if (verifyProperty != null) {
- project.setNewProperty(verifyProperty,
- new Boolean(value).toString());
- }
- }
-
- /**
- * Calculate the checksum(s)
- *
- * @return Returns true if the checksum verification test passed,
- * false otherwise.
- */
- public boolean eval() throws BuildException {
- isCondition = true;
- return validateAndExecute();
- }
-
- /**
- * Validate attributes and get down to business.
- */
- private boolean validateAndExecute() throws BuildException {
-
- if (file == null && filesets.size() == 0) {
- throw new BuildException(
- "Specify at least one source - a file or a fileset.");
- }
-
- if (file != null && file.exists() && file.isDirectory()) {
- throw new BuildException(
- "Checksum cannot be generated for directories");
- }
-
- if (property != null && fileext != null) {
- throw new BuildException(
- "Property and FileExt cannot co-exist.");
- }
-
- if (property != null) {
- if (forceOverwrite) {
- throw new BuildException(
- "ForceOverwrite cannot be used when Property is specified");
- }
-
- if (file != null) {
- if (filesets.size() > 0) {
- throw new BuildException(
- "Multiple files cannot be used when Property is specified");
- }
- } else {
- if (filesets.size() > 1) {
- throw new BuildException(
- "Multiple files cannot be used when Property is specified");
- }
- }
- }
-
- if (verifyProperty != null) {
- isCondition = true;
- }
-
- if (verifyProperty != null && forceOverwrite) {
- throw new BuildException(
- "VerifyProperty and ForceOverwrite cannot co-exist.");
- }
-
- if (isCondition && forceOverwrite) {
- throw new BuildException(
- "ForceOverwrite cannot be used when conditions are being used.");
- }
-
- if (fileext == null) {
- fileext = "." + algorithm;
- } else if (fileext.trim().length() == 0) {
- throw new BuildException(
- "File extension when specified must not be an empty string");
- }
-
- messageDigest = null;
- if (provider != null) {
- try {
- messageDigest = MessageDigest.getInstance(algorithm, provider);
- } catch (NoSuchAlgorithmException noalgo) {
- throw new BuildException(noalgo, location);
- } catch (NoSuchProviderException noprovider) {
- throw new BuildException(noprovider, location);
- }
- } else {
- try {
- messageDigest = MessageDigest.getInstance(algorithm);
- } catch (NoSuchAlgorithmException noalgo) {
- throw new BuildException(noalgo, location);
- }
- }
-
- if (messageDigest == null) {
- throw new BuildException("Unable to create Message Digest",
- location);
- }
-
- addToIncludeFileMap(file);
-
- int sizeofFileSet = filesets.size();
- for (int i = 0; i < sizeofFileSet; i++) {
- FileSet fs = (FileSet) filesets.elementAt(i);
- DirectoryScanner ds = fs.getDirectoryScanner(project);
- String[] srcFiles = ds.getIncludedFiles();
- for (int j = 0; j < srcFiles.length; j++) {
- File src = new File(fs.getDir(project), srcFiles[j]);
- addToIncludeFileMap(src);
- }
- }
-
- return generateChecksums();
- }
-
- /**
- * Add key-value pair to the hashtable upon which
- * to later operate upon.
- */
- private void addToIncludeFileMap(File file) throws BuildException {
- if (file != null) {
- if (file.exists()) {
- if (property == null) {
- File dest = new File(file.getParent(), file.getName() + fileext);
- if (forceOverwrite || isCondition ||
- (file.lastModified() > dest.lastModified())) {
- includeFileMap.put(file, dest);
- } else {
- log(file + " omitted as " + dest + " is up to date.",
- Project.MSG_VERBOSE);
- }
- } else {
- includeFileMap.put(file, property);
- }
- } else {
- String message = "Could not find file "
- + file.getAbsolutePath()
- + " to generate checksum for.";
- log(message);
- throw new BuildException(message, location);
- }
- }
- }
-
- /**
- * Generate checksum(s) using the message digest created earlier.
- */
- private boolean generateChecksums() throws BuildException {
- boolean checksumMatches = true;
- FileInputStream fis = null;
- FileOutputStream fos = null;
- try {
- for (Enumeration e = includeFileMap.keys(); e.hasMoreElements();) {
- messageDigest.reset();
- File src = (File) e.nextElement();
- if (!isCondition) {
- log("Calculating "+algorithm+" checksum for "+src);
- }
- fis = new FileInputStream(src);
- DigestInputStream dis = new DigestInputStream(fis,
- messageDigest);
- while (dis.read() != -1) {
- ;
- }
- dis.close();
- fis.close();
- fis = null;
- byte[] fileDigest = messageDigest.digest ();
- StringBuffer checksumSb = new StringBuffer();
- for (int i = 0; i < fileDigest.length; i++) {
- String hexStr = Integer.toHexString(0x00ff & fileDigest[i]);
- if (hexStr.length() < 2) {
- checksumSb.append("0");
- }
- checksumSb.append(hexStr);
- }
- String checksum = checksumSb.toString();
- //can either be a property name string or a file
- Object destination = includeFileMap.get(src);
- if (destination instanceof java.lang.String) {
- String prop = (String) destination;
- if (isCondition) {
- checksumMatches = checksum.equals(property);
- } else {
- project.setProperty(prop, checksum);
- }
- } else if (destination instanceof java.io.File) {
- if (isCondition) {
- File existingFile = (File) destination;
- if (existingFile.exists() &&
- existingFile.length() == checksum.length()) {
- fis = new FileInputStream(existingFile);
- InputStreamReader isr = new InputStreamReader(fis);
- BufferedReader br = new BufferedReader(isr);
- String suppliedChecksum = br.readLine();
- fis.close();
- fis = null;
- br.close();
- isr.close();
- checksumMatches =
- checksum.equals(suppliedChecksum);
- } else {
- checksumMatches = false;
- }
- } else {
- File dest = (File) destination;
- fos = new FileOutputStream(dest);
- fos.write(checksum.getBytes());
- fos.close();
- fos = null;
- }
- }
- }
- } catch (Exception e) {
- throw new BuildException(e, location);
- } finally {
- if (fis != null) {
- try {
- fis.close();
- } catch (IOException e) {}
- }
- if (fos != null) {
- try {
- fos.close();
- } catch (IOException e) {}
- }
- }
- return checksumMatches;
- }
- }
|