11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package org.openjdk.jigsaw;
27
28 import java.lang.module.*;
29 import java.io.*;
30 import java.net.URI;
31 import java.security.*;
32 import java.security.cert.*;
33 import java.util.*;
34 import java.util.jar.*;
35 import java.util.zip.*;
36
37 import static java.nio.file.StandardCopyOption.*;
38
39 /**
40 * A simple module library which stores data directly in the filesystem
41 *
42 * @see Library
43 */
44
45 // ## TODO: Move remaining parent-searching logic upward into Library class
46
47 // On-disk library layout
48 //
49 // $LIB/%jigsaw-library
50 // com.foo.bar/1.2.3/info (= module-info.class)
53 // classes/com/foo/bar/...
54 // resources/com/foo/bar/...
55 // lib/libbar.so
56 // bin/bar
57 // signer (signer's certchain & timestamp)
58 //
59 // ## Issue: Concurrent access to the module library
60 // ## e.g. a module is being removed while a running application
61 // ## is depending on it
62
63 public final class SimpleLibrary
64 extends Library
65 {
66
67 private static abstract class MetaData {
68
69 protected final int maxMajorVersion;
70 protected final int maxMinorVersion;
71 protected int majorVersion;
72 protected int minorVersion;
73 private FileConstants.Type type;
74 private File file;
75
76 protected MetaData(int maxMajor, int maxMinor,
77 FileConstants.Type t, File f)
78 {
79 maxMajorVersion = majorVersion = maxMajor;
80 maxMinorVersion = minorVersion = maxMinor;
81 type = t;
82 file = f;
83 }
84
85 protected abstract void storeRest(DataOutputStream out)
86 throws IOException;
87
88 void store() throws IOException {
89 OutputStream fo = new FileOutputStream(file);
90 DataOutputStream out
91 = new DataOutputStream(new BufferedOutputStream(fo));
92 try {
93 out.writeInt(FileConstants.MAGIC);
94 out.writeShort(type.value());
95 out.writeShort(majorVersion);
96 out.writeShort(minorVersion);
97 storeRest(out);
98 } finally {
99 out.close();
100 }
101 }
102
103 protected abstract void loadRest(DataInputStream in)
104 throws IOException;
105
106 protected void load() throws IOException {
107 InputStream fi = new FileInputStream(file);
108 try {
109 DataInputStream in
110 = new DataInputStream(new BufferedInputStream(fi));
111 int m = in.readInt();
112 if (m != FileConstants.MAGIC)
113 throw new IOException(file + ": Invalid magic number");
114 int typ = in.readShort();
115 if (typ != type.value())
116 throw new IOException(file + ": Invalid file type");
117 int maj = in.readShort();
118 int min = in.readShort();
119 if ( maj > maxMajorVersion
120 || (maj == maxMajorVersion && min > maxMinorVersion)) {
121 throw new IOException(file
122 + ": Futuristic version number");
123 }
124 majorVersion = maj;
125 minorVersion = min;
126 loadRest(in);
127 } catch (EOFException x) {
128 throw new IOException(file + ": Invalid library metadata",
129 x);
130 } finally {
131 fi.close();
132 }
133 }
134
135 }
136
137 /**
138 * Defines the storage options that SimpleLibrary supports.
139 */
140 public static enum StorageOption {
141 DEFLATED,
142 }
143
144 private static final class Header
145 extends MetaData
146 {
147 private static final String FILE
148 = FileConstants.META_PREFIX + "jigsaw-library";
149
150 private static final int MAJOR_VERSION = 0;
151 private static final int MINOR_VERSION = 1;
152
153 private static final int DEFLATED = 1 << 0;
154
155 private File parent;
156 private Set<StorageOption> opts;
157
158 public File parent() { return parent; }
159 public boolean isDeflated() {
160 return opts.contains(StorageOption.DEFLATED);
161 }
162
163 private Header(File root, File p, Set<StorageOption> opts) {
164 super(MAJOR_VERSION, MINOR_VERSION,
165 FileConstants.Type.LIBRARY_HEADER,
166 new File(root, FILE));
167 this.parent = p;
168 this.opts = new HashSet<>(opts);
169 }
170
171 private Header(File root) {
172 this(root, null, Collections.<StorageOption>emptySet());
173 }
174
175 protected void storeRest(DataOutputStream out)
176 throws IOException
177 {
178 int flags = 0;
179 if (isDeflated())
180 flags |= DEFLATED;
181 out.writeShort(flags);
182 out.writeByte((parent != null) ? 1 : 0);
183 if (parent != null)
184 out.writeUTF(parent.toString());
185 }
186
187 protected void loadRest(DataInputStream in)
188 throws IOException
189 {
190 opts = new HashSet<StorageOption>();
191 int flags = in.readShort();
192 if ((flags & DEFLATED) == DEFLATED)
193 opts.add(StorageOption.DEFLATED);
194 int b = in.readByte();
195 if (b != 0)
196 parent = new File(in.readUTF());
197 }
198
199 private static Header load(File f)
200 throws IOException
201 {
202 Header h = new Header(f);
203 h.load();
204 return h;
205 }
206
207 }
208
209 private final File root;
210 private final File canonicalRoot;
211 private File parentPath = null;
212 private SimpleLibrary parent = null;
213 private final Header hd;
214
215 public String name() { return root.toString(); }
216 public File root() { return canonicalRoot; }
217 public int majorVersion() { return hd.majorVersion; }
218 public int minorVersion() { return hd.minorVersion; }
219 public SimpleLibrary parent() { return parent; }
220 public boolean isDeflated() { return hd.isDeflated(); }
221
222 private URI location = null;
223 public URI location() {
224 if (location == null)
225 location = root().toURI();
226 return location;
227 }
228
229 @Override
230 public String toString() {
231 return (this.getClass().getName()
232 + "[" + canonicalRoot
233 + ", v" + hd.majorVersion + "." + hd.minorVersion + "]");
234 }
235
236 private SimpleLibrary(File path, boolean create, File parentPath, Set<StorageOption> opts)
237 throws IOException
238 {
239 root = path;
240 canonicalRoot = root.getCanonicalFile();
241 if (root.exists()) {
242 if (!root.isDirectory())
243 throw new IOException(root + ": Exists but is not a directory");
244 hd = Header.load(root);
245 if (hd.parent() != null) {
246 parent = open(hd.parent());
247 parentPath = hd.parent();
248 }
249 return;
250 }
251 if (!create)
252 throw new FileNotFoundException(root.toString());
253 if (parentPath != null) {
254 this.parent = open(parentPath);
255 this.parentPath = this.parent.root();
256 }
257 if (!root.mkdirs())
258 throw new IOException(root + ": Cannot create library directory");
259 hd = new Header(canonicalRoot, this.parentPath, opts);
260 hd.store();
261 }
262
263 public static SimpleLibrary create(File path, File parent, Set<StorageOption> opts)
264 throws IOException
265 {
266 return new SimpleLibrary(path, true, parent, opts);
267 }
268
269 public static SimpleLibrary create(File path, File parent)
270 throws IOException
271 {
272 return new SimpleLibrary(path, true, parent, Collections.<StorageOption>emptySet());
273 }
274
275 public static SimpleLibrary create(File path, Set<StorageOption> opts)
276 throws IOException
277 {
278 // ## Should default parent to $JAVA_HOME/lib/modules
279 return new SimpleLibrary(path, true, null, opts);
280 }
281
282 public static SimpleLibrary open(File path)
283 throws IOException
284 {
285 return new SimpleLibrary(path, false, null, Collections.<StorageOption>emptySet());
286 }
287
288 private static final JigsawModuleSystem jms
289 = JigsawModuleSystem.instance();
290
291 private static final class Index
292 extends MetaData
293 {
294
295 private static String FILE = "index";
296
297 private static int MAJOR_VERSION = 0;
298 private static int MINOR_VERSION = 1;
299
300 private Set<String> publicClasses;
301 public Set<String> publicClasses() { return publicClasses; }
302
303 private Set<String> otherClasses;
304 public Set<String> otherClasses() { return otherClasses; }
305
981
982 if (verifySignature && mr.hasSignature()) {
983 ModuleFileVerifier mfv = new SignedModule.PKCS7Verifier(mr);
984 if (mfvParams == null) {
985 mfvParams = new SignedModule.VerifierParameters();
986 }
987 // Verify the module signature and validate the signer's
988 // certificate chain
989 Set<CodeSigner> signers = mfv.verifySignature(mfvParams);
990
991 // Verify the module header hash and the module info hash
992 mfv.verifyHashesStart(mfvParams);
993
994 // ## Check policy - is signer trusted and what permissions
995 // ## should be granted?
996
997 // Store signer info
998 new Signers(md, signers).store();
999
1000 // Read and verify the rest of the hashes
1001 mr.readRest(md, isDeflated());
1002 mfv.verifyHashesRest(mfvParams);
1003 } else {
1004 mr.readRest(md, isDeflated());
1005 }
1006
1007 if (strip)
1008 strip(md);
1009 reIndex(mid); // ## Could do this while reading module file
1010 return mid;
1011
1012 } catch (IOException | SignatureException x) {
1013 if (md != null && md.exists()) {
1014 try {
1015 Files.deleteTree(md);
1016 } catch (IOException y) {
1017 y.initCause(x);
1018 throw y;
1019 }
1020 }
1021 throw x;
1022 }
1023 }
1024
1025 private ModuleId installFromJarFile(File mf, boolean verifySignature, boolean strip)
1026 throws ConfigurationException, IOException, SignatureException
1027 {
1028 File md = null;
1029 try (JarFile jf = new JarFile(mf, verifySignature)) {
1030 ModuleInfo mi = jf.getModuleInfo();
1031 if (mi == null)
1032 throw new ConfigurationException(mf + ": not a modular JAR file");
1033
1034 md = moduleDir(mi.id());
1035 ModuleId mid = mi.id();
1169 entry.setSize(size);
1170 entry.setCrc(je.getCrc());
1171 entry.setCompressedSize(size);
1172 }
1173 jos.putNextEntry(entry);
1174 if (baos.size() > 0)
1175 baos.writeTo(jos);
1176 jos.closeEntry();
1177 } catch (SecurityException se) {
1178 throw new SignatureException(se);
1179 }
1180 }
1181
1182 private ModuleId install(File mf, boolean verifySignature, boolean strip)
1183 throws ConfigurationException, IOException, SignatureException
1184 {
1185 ModuleId mid;
1186 if (mf.getName().endsWith(".jar"))
1187 mid = installFromJarFile(mf, verifySignature, strip);
1188 else {
1189 try (FileInputStream in = new FileInputStream(mf)) {
1190 mid = install(in, verifySignature, strip);
1191 }
1192 }
1193 return mid;
1194 }
1195
1196 public void install(Collection<File> mfs, boolean verifySignature, boolean strip)
1197 throws ConfigurationException, IOException, SignatureException
1198 {
1199 List<ModuleId> mids = new ArrayList<>();
1200 boolean complete = false;
1201 Throwable ox = null;
1202 try {
1203 for (File mf : mfs)
1204 mids.add(install(mf, verifySignature, strip));
1205 configure(mids);
1206 complete = true;
1207 } catch (IOException|ConfigurationException x) {
1208 ox = x;
1321 throws ConfigurationException, IOException
1322 {
1323 // ## mids not used yet
1324 for (ModuleInfo mi : listLocalRootModuleInfos()) {
1325 // ## We could be a lot more clever about this!
1326 Configuration<Context> cf
1327 = Configurator.configure(this, mi.id().toQuery());
1328 new StoredConfiguration(moduleDir(mi.id()), cf).store();
1329 }
1330 }
1331
1332 public URI findLocalResource(ModuleId mid, String name)
1333 throws IOException
1334 {
1335 return locateContent(mid, name);
1336 }
1337
1338 public File findLocalNativeLibrary(ModuleId mid, String name)
1339 throws IOException
1340 {
1341 File md = findModuleDir(mid);
1342 if (md == null)
1343 return null;
1344 File f = new File(new File(md, "lib"), name);
1345 if (!f.exists())
1346 return null;
1347 return f;
1348 }
1349
1350 public File classPath(ModuleId mid)
1351 throws IOException
1352 {
1353 File md = findModuleDir(mid);
1354 if (md == null) {
1355 if (parent != null)
1356 return parent.classPath(mid);
1357 return null;
1358 }
1359 // ## Check for other formats here
1360 return new File(md, "classes");
1361 }
1362
1363 /**
1364 * <p> Re-index the classes of the named previously-installed modules, and
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package org.openjdk.jigsaw;
27
28 import java.lang.module.*;
29 import java.io.*;
30 import java.net.URI;
31 import java.nio.file.*;
32 import java.security.*;
33 import java.security.cert.*;
34 import java.util.*;
35 import java.util.jar.*;
36 import java.util.zip.*;
37
38 import static java.nio.file.StandardCopyOption.*;
39
40 /**
41 * A simple module library which stores data directly in the filesystem
42 *
43 * @see Library
44 */
45
46 // ## TODO: Move remaining parent-searching logic upward into Library class
47
48 // On-disk library layout
49 //
50 // $LIB/%jigsaw-library
51 // com.foo.bar/1.2.3/info (= module-info.class)
54 // classes/com/foo/bar/...
55 // resources/com/foo/bar/...
56 // lib/libbar.so
57 // bin/bar
58 // signer (signer's certchain & timestamp)
59 //
60 // ## Issue: Concurrent access to the module library
61 // ## e.g. a module is being removed while a running application
62 // ## is depending on it
63
64 public final class SimpleLibrary
65 extends Library
66 {
67
68 private static abstract class MetaData {
69
70 protected final int maxMajorVersion;
71 protected final int maxMinorVersion;
72 protected int majorVersion;
73 protected int minorVersion;
74 private final FileConstants.Type type;
75 private final File file;
76
77 protected MetaData(int maxMajor, int maxMinor,
78 FileConstants.Type t, File f)
79 {
80 maxMajorVersion = majorVersion = maxMajor;
81 maxMinorVersion = minorVersion = maxMinor;
82 type = t;
83 file = f;
84 }
85
86 protected abstract void storeRest(DataOutputStream out)
87 throws IOException;
88
89 void store() throws IOException {
90 try (OutputStream fos = new FileOutputStream(file);
91 BufferedOutputStream bos = new BufferedOutputStream(fos);
92 DataOutputStream out = new DataOutputStream(bos)) {
93 out.writeInt(FileConstants.MAGIC);
94 out.writeShort(type.value());
95 out.writeShort(majorVersion);
96 out.writeShort(minorVersion);
97 storeRest(out);
98 }
99 }
100
101 protected abstract void loadRest(DataInputStream in)
102 throws IOException;
103
104 protected void load() throws IOException {
105 try (InputStream fis = new FileInputStream(file);
106 BufferedInputStream bis = new BufferedInputStream(fis);
107 DataInputStream in = new DataInputStream(fis)) {
108 if (in.readInt() != FileConstants.MAGIC)
109 throw new IOException(file + ": Invalid magic number");
110 if (in.readShort() != type.value())
111 throw new IOException(file + ": Invalid file type");
112 int maj = in.readShort();
113 int min = in.readShort();
114 if ( maj > maxMajorVersion
115 || (maj == maxMajorVersion && min > maxMinorVersion)) {
116 throw new IOException(file
117 + ": Futuristic version number");
118 }
119 majorVersion = maj;
120 minorVersion = min;
121 loadRest(in);
122 } catch (EOFException x) {
123 throw new IOException(file + ": Invalid library metadata", x);
124 }
125 }
126 }
127
128 /**
129 * Defines the storage options that SimpleLibrary supports.
130 */
131 public static enum StorageOption {
132 DEFLATED,
133 }
134
135 private static final class Header
136 extends MetaData
137 {
138 private static final String FILE
139 = FileConstants.META_PREFIX + "jigsaw-library";
140
141 private static final int MAJOR_VERSION = 0;
142 private static final int MINOR_VERSION = 1;
143
144 private static final int DEFLATED = 1 << 0;
145
146 private File parent;
147 // location of native libs for this library (may be outside the library)
148 // null:default, to use a per-module 'lib' directory
149 private File natlibs;
150 // location of native cmds for this library (may be outside the library)
151 // null:default, to use a per-module 'bin' directory
152 private File natcmds;
153 // location of config files for this library (may be outside the library)
154 // null:default, to use a per-module 'etc' directory
155 private File configs;
156 private Set<StorageOption> opts;
157
158 public File parent() { return parent; }
159 public File natlibs() { return natlibs; }
160 public File natcmds() { return natcmds; }
161 public File configs() { return configs; }
162 public boolean isDeflated() {
163 return opts.contains(StorageOption.DEFLATED);
164 }
165
166 private Header(File root) {
167 super(MAJOR_VERSION, MINOR_VERSION,
168 FileConstants.Type.LIBRARY_HEADER,
169 new File(root, FILE));
170 }
171
172 private Header(File root, File parent, File natlibs, File natcmds,
173 File configs, Set<StorageOption> opts) {
174 this(root);
175 this.parent = parent;
176 this.natlibs = natlibs;
177 this.natcmds = natcmds;
178 this.configs = configs;
179 this.opts = new HashSet<>(opts);
180 }
181
182 private void storePath(File p, DataOutputStream out) throws IOException {
183 if (p != null) {
184 out.writeByte(1);
185 out.writeUTF(Files.convertSeparator(p.toString()));
186 } else {
187 out.write(0);
188 }
189 }
190
191 protected void storeRest(DataOutputStream out) throws IOException {
192 int flags = 0;
193 if (isDeflated())
194 flags |= DEFLATED;
195 out.writeShort(flags);
196
197 storePath(parent, out);
198 storePath(natlibs, out);
199 storePath(natcmds, out);
200 storePath(configs, out);
201 }
202
203 private File loadPath(DataInputStream in) throws IOException {
204 if (in.readByte() != 0)
205 return new File(Files.platformSeparator(in.readUTF()));
206 return null;
207 }
208
209 protected void loadRest(DataInputStream in) throws IOException {
210 opts = new HashSet<StorageOption>();
211 int flags = in.readShort();
212 if ((flags & DEFLATED) == DEFLATED)
213 opts.add(StorageOption.DEFLATED);
214 parent = loadPath(in);
215 natlibs = loadPath(in);
216 natcmds = loadPath(in);
217 configs = loadPath(in);
218 }
219
220 private static Header load(File f) throws IOException {
221 Header h = new Header(f);
222 h.load();
223 return h;
224 }
225 }
226
227 private final File root;
228 private final File canonicalRoot;
229 private final File parentPath;
230 private final File natlibs;
231 private final File natcmds;
232 private final File configs;
233 private final SimpleLibrary parent;
234 private final Header hd;
235
236 public String name() { return root.toString(); }
237 public File root() { return canonicalRoot; }
238 public int majorVersion() { return hd.majorVersion; }
239 public int minorVersion() { return hd.minorVersion; }
240 public SimpleLibrary parent() { return parent; }
241 public File natlibs() { return natlibs; }
242 public File natcmds() { return natcmds; }
243 public File configs() { return configs; }
244 public boolean isDeflated() { return hd.isDeflated(); }
245
246 private URI location = null;
247 public URI location() {
248 if (location == null)
249 location = root().toURI();
250 return location;
251 }
252
253 @Override
254 public String toString() {
255 return (this.getClass().getName()
256 + "[" + canonicalRoot
257 + ", v" + hd.majorVersion + "." + hd.minorVersion + "]");
258 }
259
260
261 private static File resolveAndEnsurePath(File path) throws IOException {
262 if (path == null) { return null; }
263
264 File p = path.getCanonicalFile();
265 if (!p.exists()) {
266 Files.mkdirs(p, p.toString());
267 } else {
268 Files.ensureIsDirectory(p);
269 Files.ensureWriteable(p);
270 }
271 return p;
272 }
273
274 private File relativize(File path) throws IOException {
275 if (path == null) { return null; }
276 // Return the path relative to the canonical root
277 return (canonicalRoot.toPath().relativize(path.toPath().toRealPath())).toFile();
278 }
279
280 // Opens an existing library
281 private SimpleLibrary(File path) throws IOException {
282 root = path;
283 canonicalRoot = root.getCanonicalFile();
284 Files.ensureIsDirectory(root);
285 hd = Header.load(root);
286
287 parentPath = hd.parent();
288 parent = parentPath != null ? open(parentPath) : null;
289
290 natlibs = hd.natlibs() == null ? null :
291 new File(canonicalRoot, hd.natlibs().toString()).getCanonicalFile();
292 natcmds = hd.natcmds() == null ? null :
293 new File(canonicalRoot, hd.natcmds().toString()).getCanonicalFile();
294 configs = hd.configs() == null ? null :
295 new File(canonicalRoot, hd.configs().toString()).getCanonicalFile();
296 }
297
298 // Creates a new library
299 private SimpleLibrary(File path, File parentPath, File natlibs, File natcmds,
300 File configs, Set<StorageOption> opts)
301 throws IOException
302 {
303 root = path;
304 canonicalRoot = root.getCanonicalFile();
305 if (root.exists()) {
306 Files.ensureIsDirectory(root);
307 if (root.list().length != 0)
308 throw new IOException(root + ": Already Exists");
309 Files.ensureWriteable(root);
310 } else
311 Files.mkdirs(root, root.toString());
312
313 this.parent = parentPath != null ? open(parentPath) : null;
314 this.parentPath = parentPath != null ? this.parent.root() : null;
315
316 this.natlibs = resolveAndEnsurePath(natlibs);
317 this.natcmds = resolveAndEnsurePath(natcmds);
318 this.configs = resolveAndEnsurePath(configs);
319
320 hd = new Header(canonicalRoot, this.parentPath, relativize(this.natlibs),
321 relativize(this.natcmds), relativize(this.configs), opts);
322 hd.store();
323 }
324
325 public static SimpleLibrary create(File path, File parent, File natlibs,
326 File natcmds, File configs,
327 Set<StorageOption> opts)
328 throws IOException
329 {
330 return new SimpleLibrary(path, parent, natlibs, natcmds, configs, opts);
331 }
332
333 public static SimpleLibrary create(File path, File parent, Set<StorageOption> opts)
334 throws IOException
335 {
336 return new SimpleLibrary(path, parent, null, null, null, opts);
337 }
338
339 public static SimpleLibrary create(File path, File parent)
340 throws IOException
341 {
342 return SimpleLibrary.create(path, parent, Collections.<StorageOption>emptySet());
343 }
344
345 public static SimpleLibrary create(File path, Set<StorageOption> opts)
346 throws IOException
347 {
348 // ## Should default parent to $JAVA_HOME/lib/modules
349 return SimpleLibrary.create(path, null, opts);
350 }
351
352 public static SimpleLibrary open(File path)
353 throws IOException
354 {
355 return new SimpleLibrary(path);
356 }
357
358 private static final JigsawModuleSystem jms
359 = JigsawModuleSystem.instance();
360
361 private static final class Index
362 extends MetaData
363 {
364
365 private static String FILE = "index";
366
367 private static int MAJOR_VERSION = 0;
368 private static int MINOR_VERSION = 1;
369
370 private Set<String> publicClasses;
371 public Set<String> publicClasses() { return publicClasses; }
372
373 private Set<String> otherClasses;
374 public Set<String> otherClasses() { return otherClasses; }
375
1051
1052 if (verifySignature && mr.hasSignature()) {
1053 ModuleFileVerifier mfv = new SignedModule.PKCS7Verifier(mr);
1054 if (mfvParams == null) {
1055 mfvParams = new SignedModule.VerifierParameters();
1056 }
1057 // Verify the module signature and validate the signer's
1058 // certificate chain
1059 Set<CodeSigner> signers = mfv.verifySignature(mfvParams);
1060
1061 // Verify the module header hash and the module info hash
1062 mfv.verifyHashesStart(mfvParams);
1063
1064 // ## Check policy - is signer trusted and what permissions
1065 // ## should be granted?
1066
1067 // Store signer info
1068 new Signers(md, signers).store();
1069
1070 // Read and verify the rest of the hashes
1071 mr.readRest(md, isDeflated(), natlibs(), natcmds(), configs());
1072 mfv.verifyHashesRest(mfvParams);
1073 } else {
1074 mr.readRest(md, isDeflated(), natlibs(), natcmds(), configs());
1075 }
1076
1077 if (strip)
1078 strip(md);
1079 reIndex(mid); // ## Could do this while reading module file
1080 return mid;
1081
1082 } catch (IOException | SignatureException x) {
1083 if (md != null && md.exists()) {
1084 try {
1085 ModuleFile.Reader.remove(md);
1086 } catch (IOException y) {
1087 y.initCause(x);
1088 throw y;
1089 }
1090 }
1091 throw x;
1092 }
1093 }
1094
1095 private ModuleId installFromJarFile(File mf, boolean verifySignature, boolean strip)
1096 throws ConfigurationException, IOException, SignatureException
1097 {
1098 File md = null;
1099 try (JarFile jf = new JarFile(mf, verifySignature)) {
1100 ModuleInfo mi = jf.getModuleInfo();
1101 if (mi == null)
1102 throw new ConfigurationException(mf + ": not a modular JAR file");
1103
1104 md = moduleDir(mi.id());
1105 ModuleId mid = mi.id();
1239 entry.setSize(size);
1240 entry.setCrc(je.getCrc());
1241 entry.setCompressedSize(size);
1242 }
1243 jos.putNextEntry(entry);
1244 if (baos.size() > 0)
1245 baos.writeTo(jos);
1246 jos.closeEntry();
1247 } catch (SecurityException se) {
1248 throw new SignatureException(se);
1249 }
1250 }
1251
1252 private ModuleId install(File mf, boolean verifySignature, boolean strip)
1253 throws ConfigurationException, IOException, SignatureException
1254 {
1255 ModuleId mid;
1256 if (mf.getName().endsWith(".jar"))
1257 mid = installFromJarFile(mf, verifySignature, strip);
1258 else {
1259 // Assume jmod file
1260 try (FileInputStream in = new FileInputStream(mf)) {
1261 mid = install(in, verifySignature, strip);
1262 }
1263 }
1264 return mid;
1265 }
1266
1267 public void install(Collection<File> mfs, boolean verifySignature, boolean strip)
1268 throws ConfigurationException, IOException, SignatureException
1269 {
1270 List<ModuleId> mids = new ArrayList<>();
1271 boolean complete = false;
1272 Throwable ox = null;
1273 try {
1274 for (File mf : mfs)
1275 mids.add(install(mf, verifySignature, strip));
1276 configure(mids);
1277 complete = true;
1278 } catch (IOException|ConfigurationException x) {
1279 ox = x;
1392 throws ConfigurationException, IOException
1393 {
1394 // ## mids not used yet
1395 for (ModuleInfo mi : listLocalRootModuleInfos()) {
1396 // ## We could be a lot more clever about this!
1397 Configuration<Context> cf
1398 = Configurator.configure(this, mi.id().toQuery());
1399 new StoredConfiguration(moduleDir(mi.id()), cf).store();
1400 }
1401 }
1402
1403 public URI findLocalResource(ModuleId mid, String name)
1404 throws IOException
1405 {
1406 return locateContent(mid, name);
1407 }
1408
1409 public File findLocalNativeLibrary(ModuleId mid, String name)
1410 throws IOException
1411 {
1412 File f = natlibs();
1413 if (f == null) {
1414 f = findModuleDir(mid);
1415 if (f == null)
1416 return null;
1417 f = new File(f, "lib");
1418 }
1419 f = new File(f, name);
1420 if (!f.exists())
1421 return null;
1422 return f;
1423 }
1424
1425 public File classPath(ModuleId mid)
1426 throws IOException
1427 {
1428 File md = findModuleDir(mid);
1429 if (md == null) {
1430 if (parent != null)
1431 return parent.classPath(mid);
1432 return null;
1433 }
1434 // ## Check for other formats here
1435 return new File(md, "classes");
1436 }
1437
1438 /**
1439 * <p> Re-index the classes of the named previously-installed modules, and
|