1 /* 2 * Copyright (c) 2012, 2019, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 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 jdk.jpackage.internal; 27 28 import java.io.*; 29 import java.net.URL; 30 import java.util.Arrays; 31 import java.nio.channels.FileChannel; 32 import java.nio.file.FileVisitResult; 33 import java.nio.file.Files; 34 import java.nio.file.Path; 35 import java.nio.file.SimpleFileVisitor; 36 import java.nio.file.attribute.BasicFileAttributes; 37 import java.util.ArrayList; 38 import java.util.List; 39 40 /** 41 * IOUtils 42 * 43 * A collection of static utility methods. 44 */ 45 public class IOUtils { 46 47 public static void deleteRecursive(File path) throws IOException { 48 if (!path.exists()) { 49 return; 50 } 51 Path directory = path.toPath(); 52 Files.walkFileTree(directory, new SimpleFileVisitor<Path>() { 53 @Override 54 public FileVisitResult visitFile(Path file, 55 BasicFileAttributes attr) throws IOException { 56 if (Platform.getPlatform() == Platform.WINDOWS) { 57 Files.setAttribute(file, "dos:readonly", false); 58 } 59 Files.delete(file); 60 return FileVisitResult.CONTINUE; 61 } 62 63 @Override 64 public FileVisitResult preVisitDirectory(Path dir, 65 BasicFileAttributes attr) throws IOException { 66 if (Platform.getPlatform() == Platform.WINDOWS) { 67 Files.setAttribute(dir, "dos:readonly", false); 68 } 69 return FileVisitResult.CONTINUE; 70 } 71 72 @Override 73 public FileVisitResult postVisitDirectory(Path dir, IOException e) 74 throws IOException { 75 Files.delete(dir); 76 return FileVisitResult.CONTINUE; 77 } 78 }); 79 } 80 81 public static void copyRecursive(Path src, Path dest) throws IOException { 82 copyRecursive(src, dest, List.of()); 83 } 84 85 public static void copyRecursive(Path src, Path dest, 86 final List<String> excludes) throws IOException { 87 Files.walkFileTree(src, new SimpleFileVisitor<Path>() { 88 @Override 89 public FileVisitResult preVisitDirectory(final Path dir, 90 final BasicFileAttributes attrs) throws IOException { 91 if (excludes.contains(dir.toFile().getName())) { 92 return FileVisitResult.SKIP_SUBTREE; 93 } else { 94 Files.createDirectories(dest.resolve(src.relativize(dir))); 95 return FileVisitResult.CONTINUE; 96 } 97 } 98 99 @Override 100 public FileVisitResult visitFile(final Path file, 101 final BasicFileAttributes attrs) throws IOException { 102 if (!excludes.contains(file.toFile().getName())) { 103 Files.copy(file, dest.resolve(src.relativize(file))); 104 } 105 return FileVisitResult.CONTINUE; 106 } 107 }); 108 } 109 110 public static void copyFile(File sourceFile, File destFile) 111 throws IOException { 112 destFile.getParentFile().mkdirs(); 113 114 //recreate the file as existing copy may have weird permissions 115 destFile.delete(); 116 destFile.createNewFile(); 117 118 try (FileChannel source = new FileInputStream(sourceFile).getChannel(); 119 FileChannel destination = 120 new FileOutputStream(destFile).getChannel()) { 121 122 if (destination != null && source != null) { 123 destination.transferFrom(source, 0, source.size()); 124 } 125 } 126 127 //preserve executable bit! 128 if (sourceFile.canExecute()) { 129 destFile.setExecutable(true, false); 130 } 131 if (!sourceFile.canWrite()) { 132 destFile.setReadOnly(); 133 } 134 destFile.setReadable(true, false); 135 } 136 137 // run "launcher paramfile" in the directory where paramfile is kept 138 public static void run(String launcher, File paramFile) 139 throws IOException { 140 if (paramFile != null && paramFile.exists()) { 141 ProcessBuilder pb = 142 new ProcessBuilder(launcher, paramFile.getName()); 143 pb = pb.directory(paramFile.getParentFile()); 144 exec(pb); 145 } 146 } 147 148 public static void exec(ProcessBuilder pb) 149 throws IOException { 150 exec(pb, false, null); 151 } 152 153 public static void exec(ProcessBuilder pb, boolean testForPresenseOnly, 154 PrintStream consumer) throws IOException { 155 pb.redirectErrorStream(true); 156 Log.verbose("Running " 157 + Arrays.toString(pb.command().toArray(new String[0])) 158 + (pb.directory() != null ? (" in " + pb.directory()) : "")); 159 Process p = pb.start(); 160 InputStreamReader isr = new InputStreamReader(p.getInputStream()); 161 BufferedReader br = new BufferedReader(isr); 162 String lineRead; 163 String output = ""; 164 while ((lineRead = br.readLine()) != null) { 165 if (consumer != null) { 166 consumer.print(lineRead + '\n'); 167 } else { 168 Log.verbose(lineRead); 169 } 170 output += lineRead; 171 } 172 try { 173 int ret = p.waitFor(); 174 if (ret != 0 && !(testForPresenseOnly && ret != 127)) { 175 throw new IOException("Exec failed with code " 176 + ret + " command [" 177 + Arrays.toString(pb.command().toArray(new String[0])) 178 + " in " + (pb.directory() != null ? 179 pb.directory().getAbsolutePath() : 180 "unspecified directory") 181 + " output: " + output); 182 } 183 } catch (InterruptedException ex) { 184 } 185 } 186 187 public static int getProcessOutput(List<String> result, String... args) 188 throws IOException, InterruptedException { 189 190 ProcessBuilder pb = new ProcessBuilder(args); 191 192 final Process p = pb.start(); 193 194 List<String> list = new ArrayList<>(); 195 196 final BufferedReader in = 197 new BufferedReader(new InputStreamReader(p.getInputStream())); 198 final BufferedReader err = 199 new BufferedReader(new InputStreamReader(p.getErrorStream())); 200 201 Thread t = new Thread(() -> { 202 try { 203 String line; 204 while ((line = in.readLine()) != null) { 205 list.add(line); 206 } 207 } catch (IOException ioe) { 208 Log.verbose(ioe); 209 } 210 211 try { 212 String line; 213 while ((line = err.readLine()) != null) { 214 Log.error(line); 215 } 216 } catch (IOException ioe) { 217 Log.verbose(ioe); 218 } 219 }); 220 t.setDaemon(true); 221 t.start(); 222 223 int ret = p.waitFor(); 224 225 result.clear(); 226 result.addAll(list); 227 228 return ret; 229 } 230 231 static void writableOutputDir(Path outdir) throws PackagerException { 232 File file = outdir.toFile(); 233 234 if (!file.isDirectory() && !file.mkdirs()) { 235 throw new PackagerException("error.cannot-create-output-dir", 236 file.getAbsolutePath()); 237 } 238 if (!file.canWrite()) { 239 throw new PackagerException("error.cannot-write-to-output-dir", 240 file.getAbsolutePath()); 241 } 242 } 243 }