View Javadoc

    1   /*
    2    * This file is part of dependency-check-core.
    3    *
    4    * Dependency-check-core is free software: you can redistribute it and/or modify it
    5    * under the terms of the GNU General Public License as published by the Free
    6    * Software Foundation, either version 3 of the License, or (at your option) any
    7    * later version.
    8    *
    9    * Dependency-check-core is distributed in the hope that it will be useful, but
    10   * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11   * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
    12   * details.
    13   *
    14   * You should have received a copy of the GNU General Public License along with
    15   * dependency-check-core. If not, see http://www.gnu.org/licenses/.
    16   *
    17   * Copyright (c) 2012 Jeremy Long. All Rights Reserved.
    18   */
    19  package org.owasp.dependencycheck.utils;
    20
    21  import java.io.BufferedInputStream;
    22  import java.io.BufferedOutputStream;
    23  import java.io.File;
    24  import java.io.FileInputStream;
    25  import java.io.FileNotFoundException;
    26  import java.io.FileOutputStream;
    27  import java.io.IOException;
    28  import java.io.UnsupportedEncodingException;
    29  import java.net.URLDecoder;
    30  import java.util.logging.Level;
    31  import java.util.logging.Logger;
    32  import java.util.zip.ZipEntry;
    33  import java.util.zip.ZipInputStream;
    34  import org.owasp.dependencycheck.Engine;
    35
    36  /**
    37   * A collection of utilities for processing information about files.
    38   *
    39   * @author Jeremy Long (jeremy.long@owasp.org)
    40   */
    41  public final class FileUtils {
    42
    43      /**
    44       * The buffer size to use when extracting files from the archive.
    45       */
    46      private static final int BUFFER_SIZE = 4096;
    47
    48      /**
    49       * Private constructor for a utility class.
    50       */
    51      private FileUtils() {
    52      }
    53
    54      /**
    55       * Returns the (lowercase) file extension for a specified file.
    56       *
    57       * @param fileName the file name to retrieve the file extension from.
    58       * @return the file extension.
    59       */
    60      public static String getFileExtension(String fileName) {
    61          String ret = null;
    62          final int pos = fileName.lastIndexOf(".");
    63          if (pos >= 0) {
    64              ret = fileName.substring(pos + 1, fileName.length()).toLowerCase();
    65          }
    66          return ret;
    67      }
    68
    69      /**
    70       * Deletes a file. If the File is a directory it will recursively delete the
    71       * contents.
    72       *
    73       * @param file the File to delete
    74       * @throws IOException is thrown if the file could not be deleted
    75       */
    76      public static void delete(File file) throws IOException {
    77          if (file.isDirectory()) {
    78              for (File c : file.listFiles()) {
    79                  delete(c);
    80              }
    81          }
    82          if (!org.apache.commons.io.FileUtils.deleteQuietly(file)) {
    83              throw new FileNotFoundException("Failed to delete file: " + file);
    84          }
    85          /* else {
    86           //delete on exit was a bad idea. if for some reason the file can't be deleted
    87           // this will cause a newly constructed file to be deleted and a subsequent run may fail.
    88           // still not sure why a file fails to be deleted, but can be overwritten... odd.
    89           file.deleteOnExit();
    90           }*/
    91      }
    92
    93      /**
    94       * Returns the data directory. If a path was specified in
    95       * dependencycheck.properties or was specified using the Settings object,
    96       * and the path exists, that path will be returned as a File object. If it
    97       * does not exist, then a File object will be created based on the file
    98       * location of the JAR containing the specified class.
    99       *
    100      * @param configuredFilePath the configured relative or absolute path
    101      * @param clazz the class whos path will be resolved
    102      * @return a File object
    103      * @throws IOException is thrown if the path could not be decoded
    104      * @deprecated This method should no longer be used. See the implementation
    105      * in dependency-check-cli/App.java to see how the data directory should be
    106      * set.
    107      */
    108     @java.lang.Deprecated
    109     public static File getDataDirectory(String configuredFilePath, Class clazz) throws IOException {
    110         final File file = new File(configuredFilePath);
    111         if (file.isDirectory() && file.canWrite()) {
    112             return new File(file.getCanonicalPath());
    113         } else {
    114             final File exePath = getPathToJar(clazz);
    115             return new File(exePath, configuredFilePath);
    116         }
    117     }
    118
    119     /**
    120      * Retrieves the physical path to the parent directory containing the
    121      * provided class. For example, if a JAR file contained a class
    122      * org.something.clazz this method would return the parent directory of the
    123      * JAR file.
    124      *
    125      * @param clazz the class to determine the parent directory of
    126      * @return the parent directory of the file containing the specified class.
    127      * @throws UnsupportedEncodingException thrown if UTF-8 is not supported.
    128      * @deprecated this should no longer be used.
    129      */
    130     @java.lang.Deprecated
    131     public static File getPathToJar(Class clazz) throws UnsupportedEncodingException {
    132         final String filePath = clazz.getProtectionDomain().getCodeSource().getLocation().getPath();
    133         final String decodedPath = URLDecoder.decode(filePath, "UTF-8");
    134         final File jarPath = new File(decodedPath);
    135         return jarPath.getParentFile();
    136     }
    137
    138     /**
    139      * Extracts the contents of an archive into the specified directory.
    140      *
    141      * @param archive an archive file such as a WAR or EAR
    142      * @param extractTo a directory to extract the contents to
    143      * @throws ExtractionException thrown if an exception occurs while
    144      * extracting the files
    145      */
    146     public static void extractFiles(File archive, File extractTo) throws ExtractionException {
    147         extractFiles(archive, extractTo, null);
    148     }
    149
    150     /**
    151      * Extracts the contents of an archive into the specified directory. The
    152      * files are only extracted if they are supported by the analyzers loaded
    153      * into the specified engine. If the engine is specified as null then all
    154      * files are extracted.
    155      *
    156      * @param archive an archive file such as a WAR or EAR
    157      * @param extractTo a directory to extract the contents to
    158      * @param engine the scanning engine
    159      * @throws ExtractionException thrown if there is an error extracting the
    160      * files
    161      */
    162     public static void extractFiles(File archive, File extractTo, Engine engine) throws ExtractionException {
    163         if (archive == null || extractTo == null) {
    164             return;
    165         }
    166
    167         FileInputStream fis = null;
    168         ZipInputStream zis = null;
    169
    170         try {
    171             fis = new FileInputStream(archive);
    172         } catch (FileNotFoundException ex) {
    173             Logger.getLogger(FileUtils.class.getName()).log(Level.INFO, null, ex);
    174             throw new ExtractionException("Archive file was not found.", ex);
    175         }
    176         zis = new ZipInputStream(new BufferedInputStream(fis));
    177         ZipEntry entry;
    178         try {
    179             while ((entry = zis.getNextEntry()) != null) {
    180                 if (entry.isDirectory()) {
    181                     final File d = new File(extractTo, entry.getName());
    182                     if (!d.exists() && !d.mkdirs()) {
    183                         final String msg = String.format("Unable to create '%s'.", d.getAbsolutePath());
    184                         throw new ExtractionException(msg);
    185                     }
    186                 } else {
    187                     final File file = new File(extractTo, entry.getName());
    188                     final String ext = getFileExtension(file.getName());
    189                     if (engine == null || engine.supportsExtension(ext)) {
    190                         BufferedOutputStream bos = null;
    191                         FileOutputStream fos;
    192                         try {
    193                             fos = new FileOutputStream(file);
    194                             bos = new BufferedOutputStream(fos, BUFFER_SIZE);
    195                             int count;
    196                             final byte data[] = new byte[BUFFER_SIZE];
    197                             while ((count = zis.read(data, 0, BUFFER_SIZE)) != -1) {
    198                                 bos.write(data, 0, count);
    199                             }
    200                             bos.flush();
    201                         } catch (FileNotFoundException ex) {
    202                             Logger.getLogger(FileUtils.class.getName()).log(Level.FINE, null, ex);
    203                             final String msg = String.format("Unable to find file '%s'.", file.getName());
    204                             throw new ExtractionException(msg, ex);
    205                         } catch (IOException ex) {
    206                             Logger.getLogger(FileUtils.class.getName()).log(Level.FINE, null, ex);
    207                             final String msg = String.format("IO Exception while parsing file '%s'.", file.getName());
    208                             throw new ExtractionException(msg, ex);
    209                         } finally {
    210                             if (bos != null) {
    211                                 try {
    212                                     bos.close();
    213                                 } catch (IOException ex) {
    214                                     Logger.getLogger(FileUtils.class.getName()).log(Level.FINEST, null, ex);
    215                                 }
    216                             }
    217                         }
    218                     }
    219                 }
    220             }
    221         } catch (IOException ex) {
    222             final String msg = String.format("Exception reading archive '%s'.", archive.getName());
    223             Logger.getLogger(FileUtils.class.getName()).log(Level.FINE, msg, ex);
    224             throw new ExtractionException(msg, ex);
    225         } finally {
    226             try {
    227                 zis.close();
    228             } catch (IOException ex) {
    229                 Logger.getLogger(FileUtils.class.getName()).log(Level.FINEST, null, ex);
    230             }
    231         }
    232     }
    233 }