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 protected void storeRest(DataOutputStream out) throws IOException {
191 int flags = 0;
192 if (isDeflated())
193 flags |= DEFLATED;
194 out.writeShort(flags);
195
196 storePath(parent, out);
197 storePath(natlibs, out);
198 storePath(natcmds, out);
199 storePath(configs, out);
200 }
201
202 private File loadPath(DataInputStream in) throws IOException {
203 if (in.readByte() != 0)
204 return new File(Files.platformSeparator(in.readUTF()));
205 return null;
206 }
207
208 protected void loadRest(DataInputStream in) throws IOException {
209 opts = new HashSet<StorageOption>();
210 int flags = in.readShort();
211 if ((flags & DEFLATED) == DEFLATED)
212 opts.add(StorageOption.DEFLATED);
213 parent = loadPath(in);
214 natlibs = loadPath(in);
215 natcmds = loadPath(in);
216 configs = loadPath(in);
217 }
218
219 private static Header load(File f) throws IOException {
220 Header h = new Header(f);
221 h.load();
222 return h;
223 }
224 }
225
226 private final File root;
227 private final File canonicalRoot;
228 private File parentPath;
229 private File natlibs;
230 private File natcmds;
231 private File configs;
232 private SimpleLibrary parent;
233 private final Header hd;
234
235 public String name() { return root.toString(); }
236 public File root() { return canonicalRoot; }
237 public int majorVersion() { return hd.majorVersion; }
238 public int minorVersion() { return hd.minorVersion; }
239 public SimpleLibrary parent() { return parent; }
240 public File natlibs() { return natlibs; }
241 public File natcmds() { return natcmds; }
242 public File configs() { return configs; }
243 public boolean isDeflated() { return hd.isDeflated(); }
244
245 private URI location = null;
246 public URI location() {
247 if (location == null)
248 location = root().toURI();
249 return location;
250 }
251
252 @Override
253 public String toString() {
254 return (this.getClass().getName()
255 + "[" + canonicalRoot
256 + ", v" + hd.majorVersion + "." + hd.minorVersion + "]");
257 }
258
259
260 private static File resolveAndEnsurePath(File path) throws IOException {
261 if (path == null) { return null; }
262
263 File p = path.getCanonicalFile();
264 if (!p.exists())
265 Files.mkdirs(p, p.toString());
266 else {
267 Files.ensureIsDirectory(p);
268 Files.ensureWriteable(p);
269 }
270 return p;
271 }
272
273 private File relativize(File path) throws IOException {
274 if (path == null) { return null; }
275 // Return the path relative to the canonical root
276 return (canonicalRoot.toPath().relativize(path.toPath().toRealPath())).toFile();
277 }
278
279 // Opens an existing library
280 private SimpleLibrary(File path) throws IOException {
281 root = path;
282 canonicalRoot = root.getCanonicalFile();
283 Files.ensureIsDirectory(root);
284 hd = Header.load(root);
285 if (hd.parent() != null) {
286 parent = open(hd.parent());
287 parentPath = hd.parent();
288 }
289
290 if (hd.natlibs() != null)
291 natlibs = new File(canonicalRoot, hd.natlibs().toString()).getCanonicalFile();
292 if (hd.natcmds() != null)
293 natcmds = new File(canonicalRoot, hd.natcmds().toString()).getCanonicalFile();
294 if (hd.configs() != null)
295 configs = 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 if (parentPath != null) {
314 this.parent = open(parentPath);
315 this.parentPath = this.parent.root();
316 }
317
318 this.natlibs = resolveAndEnsurePath(natlibs);
319 this.natcmds = resolveAndEnsurePath(natcmds);
320 this.configs = resolveAndEnsurePath(configs);
321
322 hd = new Header(canonicalRoot, this.parentPath, relativize(this.natlibs),
323 relativize(this.natcmds), relativize(this.configs), opts);
324 hd.store();
325 }
326
327 public static SimpleLibrary create(File path, File parent, File natlibs,
328 File natcmds, File configs,
329 Set<StorageOption> opts)
330 throws IOException
331 {
332 return new SimpleLibrary(path, parent, natlibs, natcmds, configs, opts);
333 }
334
335 public static SimpleLibrary create(File path, File parent, Set<StorageOption> opts)
336 throws IOException
337 {
338 return new SimpleLibrary(path, parent, null, null, null, opts);
339 }
340
341 public static SimpleLibrary create(File path, File parent)
342 throws IOException
343 {
344 return SimpleLibrary.create(path, parent, Collections.<StorageOption>emptySet());
345 }
346
347 public static SimpleLibrary create(File path, Set<StorageOption> opts)
348 throws IOException
349 {
350 // ## Should default parent to $JAVA_HOME/lib/modules
351 return SimpleLibrary.create(path, null, opts);
352 }
353
354 public static SimpleLibrary open(File path)
355 throws IOException
356 {
357 return new SimpleLibrary(path);
358 }
359
360 private static final JigsawModuleSystem jms
361 = JigsawModuleSystem.instance();
362
363 private static final class Index
364 extends MetaData
365 {
366
367 private static String FILE = "index";
368
369 private static int MAJOR_VERSION = 0;
370 private static int MINOR_VERSION = 1;
371
372 private Set<String> publicClasses;
373 public Set<String> publicClasses() { return publicClasses; }
374
375 private Set<String> otherClasses;
376 public Set<String> otherClasses() { return otherClasses; }
377
1053
1054 if (verifySignature && mr.hasSignature()) {
1055 ModuleFileVerifier mfv = new SignedModule.PKCS7Verifier(mr);
1056 if (mfvParams == null) {
1057 mfvParams = new SignedModule.VerifierParameters();
1058 }
1059 // Verify the module signature and validate the signer's
1060 // certificate chain
1061 Set<CodeSigner> signers = mfv.verifySignature(mfvParams);
1062
1063 // Verify the module header hash and the module info hash
1064 mfv.verifyHashesStart(mfvParams);
1065
1066 // ## Check policy - is signer trusted and what permissions
1067 // ## should be granted?
1068
1069 // Store signer info
1070 new Signers(md, signers).store();
1071
1072 // Read and verify the rest of the hashes
1073 mr.readRest(md, isDeflated(), natlibs(), natcmds(), configs());
1074 mfv.verifyHashesRest(mfvParams);
1075 } else {
1076 mr.readRest(md, isDeflated(), natlibs(), natcmds(), configs());
1077 }
1078
1079 if (strip)
1080 strip(md);
1081 reIndex(mid); // ## Could do this while reading module file
1082 return mid;
1083
1084 } catch (IOException | SignatureException x) {
1085 if (md != null && md.exists()) {
1086 try {
1087 ModuleFile.Reader.remove(md);
1088 } catch (IOException y) {
1089 y.initCause(x);
1090 throw y;
1091 }
1092 }
1093 throw x;
1094 }
1095 }
1096
1097 private ModuleId installFromJarFile(File mf, boolean verifySignature, boolean strip)
1098 throws ConfigurationException, IOException, SignatureException
1099 {
1100 File md = null;
1101 try (JarFile jf = new JarFile(mf, verifySignature)) {
1102 ModuleInfo mi = jf.getModuleInfo();
1103 if (mi == null)
1104 throw new ConfigurationException(mf + ": not a modular JAR file");
1105
1106 md = moduleDir(mi.id());
1107 ModuleId mid = mi.id();
1241 entry.setSize(size);
1242 entry.setCrc(je.getCrc());
1243 entry.setCompressedSize(size);
1244 }
1245 jos.putNextEntry(entry);
1246 if (baos.size() > 0)
1247 baos.writeTo(jos);
1248 jos.closeEntry();
1249 } catch (SecurityException se) {
1250 throw new SignatureException(se);
1251 }
1252 }
1253
1254 private ModuleId install(File mf, boolean verifySignature, boolean strip)
1255 throws ConfigurationException, IOException, SignatureException
1256 {
1257 ModuleId mid;
1258 if (mf.getName().endsWith(".jar"))
1259 mid = installFromJarFile(mf, verifySignature, strip);
1260 else {
1261 // Assume jmod file
1262 try (FileInputStream in = new FileInputStream(mf)) {
1263 mid = install(in, verifySignature, strip);
1264 }
1265 }
1266 return mid;
1267 }
1268
1269 public void install(Collection<File> mfs, boolean verifySignature, boolean strip)
1270 throws ConfigurationException, IOException, SignatureException
1271 {
1272 List<ModuleId> mids = new ArrayList<>();
1273 boolean complete = false;
1274 Throwable ox = null;
1275 try {
1276 for (File mf : mfs)
1277 mids.add(install(mf, verifySignature, strip));
1278 configure(mids);
1279 complete = true;
1280 } catch (IOException|ConfigurationException x) {
1281 ox = x;
1394 throws ConfigurationException, IOException
1395 {
1396 // ## mids not used yet
1397 for (ModuleInfo mi : listLocalRootModuleInfos()) {
1398 // ## We could be a lot more clever about this!
1399 Configuration<Context> cf
1400 = Configurator.configure(this, mi.id().toQuery());
1401 new StoredConfiguration(moduleDir(mi.id()), cf).store();
1402 }
1403 }
1404
1405 public URI findLocalResource(ModuleId mid, String name)
1406 throws IOException
1407 {
1408 return locateContent(mid, name);
1409 }
1410
1411 public File findLocalNativeLibrary(ModuleId mid, String name)
1412 throws IOException
1413 {
1414 File f = natlibs();
1415 if (f == null) {
1416 f = findModuleDir(mid);
1417 if (f == null)
1418 return null;
1419 f = new File(f, "lib");
1420 }
1421 f = new File(f, name);
1422 if (!f.exists())
1423 return null;
1424 return f;
1425 }
1426
1427 public File classPath(ModuleId mid)
1428 throws IOException
1429 {
1430 File md = findModuleDir(mid);
1431 if (md == null) {
1432 if (parent != null)
1433 return parent.classPath(mid);
1434 return null;
1435 }
1436 // ## Check for other formats here
1437 return new File(md, "classes");
1438 }
1439
1440 /**
1441 * <p> Re-index the classes of the named previously-installed modules, and
|