src/share/classes/org/openjdk/jigsaw/ModuleFile.java

Print this page

        

@@ -60,10 +60,13 @@
 
         private DataInputStream stream;
         private File destination;
         private boolean deflate;
         private HashType hashtype;
+        private File natlibs;
+        private File natcmds;
+        private File configs;
 
         private static class CountingInputStream extends FilterInputStream {
             int count;
             public CountingInputStream(InputStream stream, int count) {
                 super(stream);

@@ -178,16 +181,26 @@
             }
         }
 
         public void readRest() throws IOException {
             extract = false;
-            readRest(null, false);
+            readRest(null, false, null, null, null);
         }
 
         public void readRest(File dst, boolean deflate) throws IOException {
-            this.destination = dst;
+            readRest(dst, deflate, null, null, null);
+        }
+
+        public void readRest(File dst, boolean deflate, File natlibs,
+                             File natcmds, File configs)
+                throws IOException
+        {
+            this.destination = dst.getCanonicalFile();
             this.deflate = deflate;
+            this.natlibs = natlibs != null ? natlibs : new File(destination, "lib");
+            this.natcmds = natcmds != null ? natcmds : new File(destination, "bin");
+            this.configs = configs != null ? configs : new File(destination, "etc");
             try {
                 if (extract)
                     Files.store(moduleInfoBytes, computeRealPath("info"));
                 // Module-Info and Signature, if present, have been consumed
 

@@ -258,10 +271,11 @@
             return contentStream;
         }
 
         public void close() throws IOException {
             try {
+                try {
                 if (contentStream != null) {
                     contentStream.close();
                     contentStream = null;
                 }
             } finally {

@@ -268,12 +282,19 @@
                 if (fileIn != null) {
                     fileIn.close();
                     fileIn = null;
                 }
             }
+            } finally {
+                if (filesWriter != null) {
+                    filesWriter.close();
+                    filesWriter = null;
         }
+            }
+        }
 
+
         public void readModule() throws IOException {
             extract = false;
             readStart();
             readRest();
         }

@@ -428,11 +449,11 @@
                  OutputStream out = openOutputStream(type, header.getPath())) {
                 copyStream(gin, out);
             }
 
             if (extract)
-                markNativeCodeExecutable(type, currentPath);
+                postExtract(type, currentPath);
         }
 
         public void readUncompressedFile(DataInputStream in,
                                          SectionType type,
                                          int csize)

@@ -446,12 +467,14 @@
                 byte[] buf = new byte[8192];
                 int n;
                 while ((n = cin.read(buf)) >= 0)
                     out.write(buf, 0, n);
             }
-            markNativeCodeExecutable(type, currentPath);
+            if (extract) {
+                postExtract(type, currentPath);
          }
+         }
 
         public byte[] readModuleInfo(DataInputStream in, int csize)
             throws IOException
         {
             CountingInputStream cin = new CountingInputStream(in, csize);

@@ -467,32 +490,82 @@
             throws IOException
         {
             return readModuleInfo(in, csize); // signature has the same format
         }
 
-        private File computeRealPath(String storedpath) throws IOException {
+        // Track files installed outside the module library. For later removal.
+        // files are relative to the modules directory.
+        private PrintWriter filesWriter;
 
-            String convertedpath = storedpath.replace('/', File.separatorChar);
-            File path = new File(convertedpath);
+        private void trackFiles(SectionType type, File file)
+            throws IOException
+        {
+            if (file == null || file.toPath().startsWith(destination.toPath()))
+                return;
 
-            // Absolute path names are not permitted.
-            ensureNonAbsolute(path);
-            path = resolveAndNormalize(destination, convertedpath);
-            // Create the parent directories if necessary
-            File parent = path.getParentFile();
-            if (!parent.exists())
-                Files.mkdirs(parent, path.getName());
+            // Lazy construction, not all modules will need this.
+            if (filesWriter == null)
+                filesWriter = new PrintWriter(computeRealPath("files"), "UTF-8");
 
-            return path;
+            filesWriter.println(Files.convertSeparator(relativize(destination, file)));
+            filesWriter.flush();
         }
 
-        private File computeRealPath(SectionType type,
-                                     String storedpath)
+        void remove() throws IOException {
+            ModuleFile.Reader.remove(destination);
+        }
+
+        // Removes a module, given its module install directory
+        static void remove(File moduleDir) throws IOException {
+            // Firstly remove any files installed outside of the module dir
+            File files = new File(moduleDir, "files");
+            if (files.exists()) {
+                try (FileInputStream fis = new FileInputStream(files);
+                     InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
+                     BufferedReader in = new BufferedReader(isr)) {
+                    String filename;
+                    while ((filename = in.readLine()) != null)
+                        Files.delete(new File(moduleDir,
+                                              Files.platformSeparator(filename)));
+                }
+            }
+
+            Files.deleteTree(moduleDir);
+        }
+
+        // Returns the absolute path of the given section type.
+        private File getDirOfSection(SectionType type) {
+            if (type == SectionType.NATIVE_LIBS)
+                return natlibs; 
+            else if (type == SectionType.NATIVE_CMDS)
+                return natcmds;
+            else if (type == SectionType.CONFIG)
+                return configs;
+
+            // resolve sub dir section paths against the modules directory
+            return new File(destination, ModuleFile.getSubdirOfSection(type));
+        }
+
+        private File computeRealPath(String path) throws IOException {
+            return resolveAndNormalize(destination, path);
+        }
+
+        private File computeRealPath(SectionType type, String storedpath)
             throws IOException
         {
-            String dir = getSubdirOfSection(type);
-            return computeRealPath(dir + File.separatorChar + storedpath);
+            File sectionPath = getDirOfSection(type);
+            File realpath = new File(sectionPath,
+                 Files.ensureNonAbsolute(Files.platformSeparator(storedpath)));
+
+            validatePath(sectionPath, realpath);
+
+            // Create the parent directories if necessary
+            File parent = realpath.getParentFile();
+            if (!parent.exists())
+                Files.mkdirs(parent, realpath.getName());
+
+            return realpath;
         }
 
         private static void markNativeCodeExecutable(SectionType type,
                                                      File file)
         {

@@ -502,10 +575,17 @@
                 {
                     file.setExecutable(true);
                 }
         }
 
+        private void postExtract(SectionType type, File path)
+            throws IOException
+        {
+            markNativeCodeExecutable(type, path);
+            trackFiles(type, path);
+        }
+
         private void unpack200gzip(DataInputStream in) throws IOException {
             GZIPInputStream gis = new GZIPInputStream(in) {
                     public void close() throws IOException {}
                 };
             Pack200.Unpacker unpacker = Pack200.newUnpacker();

@@ -577,15 +657,10 @@
         throws IOException
     {
         copyStream(in, (DataOutput) new DataOutputStream(out), count);
     }
 
-    private static void ensureNonAbsolute(File path) throws IOException {
-        if (path.isAbsolute())
-            throw new IOException("Abolute path instead of relative: " + path);
-    }
-
     private static void ensureNonNegativity(long size, String parameter) {
         if (size < 0)
             throw new IllegalArgumentException(parameter + "<0: " + size);
     }
 

@@ -674,10 +749,26 @@
             throw new IOException("Bogus relative path: " + path);
 
         return realpath;
     }
 
+
+    private static String relativize(File directory, File path) throws IOException {
+        return (directory.toPath().relativize(path.toPath().toRealPath())).toString();
+    }
+
+    private static void validatePath(File parent, File child)
+        throws IOException
+    {
+        if (!child.toPath().startsWith(parent.toPath()) )
+            throw new IOException("Bogus relative path: " + child);
+        if (child.exists()) {
+            // conflict, for now just fail
+            throw new IOException("File " + child + " already exists");
+        }
+    }
+
     private static short readHashLength(DataInputStream in) throws IOException {
         final short hashLength = in.readShort();
         ensureNonNegativity(hashLength, "hashLength");
 
         return hashLength;