1 /*
   2  * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @summary test module file hashing.
  27  */
  28 
  29 import java.io.*;
  30 import java.security.*;
  31 import java.util.*;
  32 import org.openjdk.jigsaw.*;
  33 import org.openjdk.jigsaw.cli.*;
  34 
  35 public class ModuleFormatHeaderHashTest {
  36     final String MNAME = "hello";
  37     final String MVER = "0.1";
  38     String moduleinfo = "module " + MNAME + " @ " + MVER + " {}";
  39 
  40     public static void main(String[] args) throws Exception {
  41         new ModuleFormatHeaderHashTest().run();
  42     }
  43 
  44     void run() throws Exception {
  45         try {
  46             test();
  47         } catch (Throwable t) {
  48             t.printStackTrace();
  49             errors++;
  50         }
  51 
  52 
  53         if (errors == 0)
  54             System.out.println(count + " tests passed");
  55         else
  56             throw new Exception(errors + "/" + count + " tests failed");
  57     }
  58 
  59     void testEmptyModule() throws Exception {
  60         System.err.println("Test: Empty module");
  61         count++;
  62         reset();
  63         List<File> files = new ArrayList<File>();
  64         addFile(files, createFile("module-info.java", moduleinfo));
  65         compile(files);
  66         compress(MNAME);
  67         byte [] expected = readHash(MNAME, MVER);
  68         byte [] computed = hash(MNAME, MVER, "SHA-256");
  69         if (!MessageDigest.isEqual(expected, computed))
  70             throw new IOException("Expected and computed file hashes don't match");
  71     }
  72 
  73     void test() throws Exception {
  74         testEmptyModule();
  75     }
  76 
  77     /**
  78      * Get a module file's stored hash.
  79      */
  80     byte [] readHash(String name, String version) throws Exception {
  81         String fname = moduleDir + File.separator + name + "@" + version + ".jmod";
  82         try (FileInputStream fis = new FileInputStream(fname);
  83              DataInputStream in = new DataInputStream(fis);
  84              ModuleFile.Reader r = new ModuleFile.Reader(in);) {
  85              return r.getHash();
  86         }
  87     }
  88 
  89     /**
  90      * Hash a module file (without the file hash in the module file header).
  91      */

  92     byte [] hash(String name, String version, String digest) throws Exception {
  93         String fname = moduleDir + File.separator + name + "@" + version + ".jmod";
  94         MessageDigest md = MessageDigest.getInstance(digest);
  95         try (FileInputStream fis = new FileInputStream(fname);
  96              DigestInputStream dis = new DigestInputStream(fis, md)) {
  97             dis.read(new byte[ModuleFile.ModuleFileHeader.LENGTH_WITHOUT_HASH]);
  98             dis.on(false);
  99             dis.read(new byte [md.getDigestLength()]);
 100             dis.on(true);
 101             for (int c = dis.read() ; c != -1 ; c = dis.read())
 102                 ;
 103             return md.digest();
 104         }
 105     }
 106 
 107     /**
 108      * Compress a module.
 109      */
 110     void compress(String name) throws Exception {
 111         compress(name, false);
 112     }
 113 
 114     void compress(String name, boolean haveNatLibs)
 115         throws Exception {
 116         compress(name, haveNatLibs, false);
 117     }
 118 
 119     void compress(String name, boolean haveNatLibs,
 120                   boolean haveNatCmds) throws Exception {
 121         compress(name, haveNatLibs, haveNatCmds, false);
 122     }
 123 
 124     void compress(String name, boolean haveNatLibs,
 125                   boolean haveNatCmds, boolean haveConfig)
 126         throws Exception {
 127         List<String> args = new ArrayList<String>();
 128         args.add("-m");
 129         args.add(classesDir.getAbsolutePath());
 130         args.add("-d");
 131         args.add(moduleDir.getAbsolutePath());
 132         if (haveNatLibs) {
 133             args.add("--natlib");
 134             args.add(natlibDir.toString());
 135         }
 136         if (haveNatCmds) {
 137             args.add("--natcmd");
 138             args.add(natcmdDir.toString());
 139         }
 140         if (haveConfig) {
 141             args.add("--config");
 142             args.add(configDir.toString());
 143         }
 144         args.add("jmod");
 145         args.add("hello");
 146         Packager.main(args.toArray(new String[0]));
 147     }
 148 
 149     /**
 150      * Compile a list of files.
 151      */
 152     void compile(List<File> files) {
 153         List<String> options = new ArrayList<String>();
 154         options.addAll(Arrays.asList("-source", "8", "-d", classesDir.getPath()));
 155         for (File f: files)
 156             options.add(f.getPath());
 157 
 158         String[] opts = options.toArray(new String[options.size()]);
 159         StringWriter sw = new StringWriter();
 160         try (PrintWriter pw = new PrintWriter(sw)) {
 161             int rc = com.sun.tools.javac.Main.compile(opts, pw);
 162 
 163             String out = sw.toString();
 164             if (out.trim().length() > 0)
 165                 System.err.println(out);
 166             if (rc != 0)
 167                 throw new Error("compilation failed: rc=" + rc);
 168         }
 169     }
 170 
 171     /**
 172      * Add a file to a list if the file is not null.
 173      */
 174     void addFile(List<File> files, File file) {
 175         if (file != null)
 176             files.add(file);
 177     }
 178 
 179 
 180     /**
 181      * Create a test file with given content if the content is not null.
 182      */
 183     File createFile(String path, String body) throws IOException {
 184         if (body == null)
 185             return null;
 186         File file = new File(srcDir, path);
 187         file.getAbsoluteFile().getParentFile().mkdirs();
 188         try (FileWriter out = new FileWriter(file)) {
 189             out.write(body);
 190         }
 191         return file;
 192     }
 193 
 194     /**
 195      * Set up empty src and classes directories for a test.
 196      */
 197     void reset() {
 198         resetDir(srcDir);
 199         resetDir(classesDir);
 200         resetDir(moduleDir);
 201         resetDir(new File(MNAME));
 202     }
 203 
 204     /**
 205      * Set up an empty directory.
 206      */
 207     void resetDir(File dir) {
 208         if (dir.exists())
 209             deleteAll(dir);
 210         dir.mkdirs();
 211     }
 212 
 213     /**
 214      * Delete a file or a directory (including all its contents).
 215      */
 216     boolean deleteAll(File file) {
 217         if (file.isDirectory()) {
 218             for (File f: file.listFiles())
 219                 deleteAll(f);
 220         }
 221         return file.delete();
 222     }
 223 
 224     /**
 225      * Report an error.
 226      */
 227     void error(String msg, String... more) {
 228         System.err.println("error: " + msg);
 229         for (String s: more)
 230             System.err.println(s);
 231         errors++;
 232     }
 233 
 234     int count;
 235     int errors;
 236     File srcDir = new File("tmp", "src"); // use "tmp" to help avoid accidents
 237     File classesDir = new File("tmp", "classes");
 238     File moduleDir = new File("tmp", "modules");
 239     File natlibDir = new File(srcDir, "natlib");
 240     File natcmdDir = new File(srcDir, "natcmd");
 241     File configDir = new File(srcDir, "config");
 242 }
--- EOF ---