• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 Code Intelligence GmbH
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 package com.code_intelligence.jazzer.tools;
16 
17 import java.io.IOException;
18 import java.net.URI;
19 import java.net.URISyntaxException;
20 import java.nio.file.FileSystem;
21 import java.nio.file.FileSystems;
22 import java.nio.file.Files;
23 import java.nio.file.Path;
24 import java.nio.file.Paths;
25 import java.util.Arrays;
26 import java.util.Collections;
27 import java.util.Comparator;
28 import java.util.HashMap;
29 import java.util.Map;
30 import java.util.TimeZone;
31 import java.util.stream.Collectors;
32 import java.util.stream.Stream;
33 
34 public class JarStripper {
35   private static final Map<String, String> ZIP_FS_PROPERTIES = new HashMap<>();
36   static {
37     // We copy the input to the output path before modifying, so don't try to create a new file at
38     // that path if something went wrong.
39     ZIP_FS_PROPERTIES.put("create", "false");
40   }
41 
main(String[] args)42   public static void main(String[] args) {
43     if (args.length < 2) {
44       System.err.println(
45           "Hermetically removes files and directories from .jar files by relative paths.");
46       System.err.println("Usage: in.jar out.jar [relative path]...");
47       System.exit(1);
48     }
49 
50     Path inFile = Paths.get(args[0]);
51     Path outFile = Paths.get(args[1]);
52     Iterable<String> pathsToDelete =
53         Collections.unmodifiableList(Arrays.stream(args).skip(2).collect(Collectors.toList()));
54 
55     try {
56       Files.copy(inFile, outFile);
57       if (!outFile.toFile().setWritable(true)) {
58         System.err.printf("Failed to make %s writable", outFile);
59         System.exit(1);
60       }
61     } catch (IOException e) {
62       e.printStackTrace();
63       System.exit(1);
64     }
65 
66     URI outUri = null;
67     try {
68       outUri = new URI("jar", outFile.toUri().toString(), null);
69     } catch (URISyntaxException e) {
70       e.printStackTrace();
71       System.exit(1);
72     }
73 
74     // Ensure that the ZipFileSystem uses a system-independent time zone for mtimes.
75     // https://github.com/openjdk/jdk/blob/4d64076058a4ec5df101b06572195ed5fdee6f64/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipUtils.java#L241
76     TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
77 
78     try (FileSystem zipFs = FileSystems.newFileSystem(outUri, ZIP_FS_PROPERTIES)) {
79       for (String pathToDelete : pathsToDelete) {
80         // Visit files before the directory they are contained in by sorting in reverse order.
81         try (Stream<Path> walk = Files.walk(zipFs.getPath(pathToDelete))) {
82           Iterable<Path> subpaths =
83               walk.sorted(Comparator.reverseOrder()).collect(Collectors.toList());
84           for (Path subpath : subpaths) {
85             Files.delete(subpath);
86           }
87         }
88       }
89     } catch (IOException e) {
90       e.printStackTrace();
91       System.exit(1);
92     }
93   }
94 }
95