1 /* 2 * Copyright (c) 2009, 2011, 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 org.openjdk.jigsaw; 27 28 import java.io.*; 29 import java.nio.file.attribute.BasicFileAttributes; 30 import java.nio.file.FileVisitor; 31 import java.nio.file.FileVisitResult; 32 import java.nio.file.Path; 33 import java.util.ArrayList; 34 import java.util.List; 35 import java.util.jar.*; 36 import java.util.zip.*; 37 import static java.nio.file.StandardCopyOption.COPY_ATTRIBUTES; 38 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; 39 import static java.lang.String.format; 40 41 public final class Files { 42 43 private Files() { } 44 45 // paths are stored with a platform agnostic separator, '/' 46 static String convertSeparator(String path) { 47 return path.replace(File.separatorChar, '/'); 48 } 49 50 static String platformSeparator(String path) { 51 return path.replace('/', File.separatorChar); 52 } 53 54 static void ensureWriteable(File path) throws IOException { 55 if (!path.canWrite()) 56 throw new IOException(path + ": is not writeable."); 57 } 58 59 static String ensureNonAbsolute(String path) throws IOException { 60 if ((new File(path)).isAbsolute()) 61 throw new IOException("Abolute path instead of relative: " + path); 62 return path; 63 } 64 65 static void ensureIsDirectory(File path) throws IOException { 66 if (!path.exists() || !path.isDirectory()) 67 throw new IOException(path + ": Not a directory"); 68 } 69 70 private static void ensureIsFile(File path) 71 throws IOException 72 { 73 if (!path.exists() || !path.isFile()) 74 throw new IOException(path + ": Not a file"); 75 } 76 77 private static String[] list(File dir) 78 throws IOException 79 { 80 ensureIsDirectory(dir); 81 String[] fs = dir.list(); 82 if (fs == null) 83 throw new IOException(dir + ": Cannot list directory contents"); 84 return fs; 85 } 86 87 private static File[] listFiles(File dir) 88 throws IOException 89 { 90 ensureIsDirectory(dir); 91 File[] fs = dir.listFiles(); 92 if (fs == null) 93 throw new IOException(dir + ": Cannot list directory contents"); 94 return fs; 95 } 96 97 public static void delete(File path) 98 throws IOException 99 { 100 if (!path.delete()) 101 throw new IOException(path + ": Cannot delete"); 102 } 103 104 public static void deleteTree(File dst) 105 throws IOException 106 { 107 File[] fs = listFiles(dst); 108 for (int i = 0; i < fs.length; i++) { 109 File f = fs[i]; 110 if (f.isDirectory()) { 111 deleteTree(f); 112 } else { 113 delete(f); 114 } 115 } 116 delete(dst); 117 } 118 119 static List<IOException> deleteAllUnchecked(Path dir) { 120 final List<IOException> excs = new ArrayList<>(); 121 try { 122 java.nio.file.Files.walkFileTree(dir, new FileVisitor<Path>() { 123 @Override 124 public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { 125 return FileVisitResult.CONTINUE; 126 } 127 @Override 128 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { 129 try { 130 java.nio.file.Files.delete(file); 131 } catch (IOException x) { 132 excs.add(new IOException(format("Unable to delete %s%n", file))); 133 } 134 return FileVisitResult.CONTINUE; 135 } 136 @Override 137 public FileVisitResult postVisitDirectory(Path dir, IOException exc) { 138 try { 139 java.nio.file.Files.delete(dir); 140 } catch (IOException x) { 141 excs.add(new IOException(format("Unable to delete %s%n", dir))); 142 } 143 return FileVisitResult.CONTINUE; 144 } 145 @Override 146 public FileVisitResult visitFileFailed(Path file, IOException exc) { 147 excs.add(new IOException(format("Unable to visit %s%n", file))); 148 return FileVisitResult.CONTINUE; 149 } 150 }); 151 } catch (IOException x) { 152 excs.add(x); 153 } 154 return excs; 155 } 156 157 static IOException deleteUnchecked(Path file) 158 { 159 try { 160 java.nio.file.Files.delete(file); 161 } catch (IOException exc) { 162 return new IOException(format("Unable to delete %s\n", file)); 163 } 164 return null; 165 } 166 167 168 private static void copy(File src, File dst) 169 throws IOException 170 { 171 java.nio.file.Files.copy(src.toPath(), dst.toPath(), 172 COPY_ATTRIBUTES, REPLACE_EXISTING); 173 } 174 175 public static interface Filter<T> { 176 public boolean accept(T x) throws IOException; 177 } 178 179 // src, dst are directories 180 // src must exist; dst created if it does not yet exist 181 // Copy files from src to dst, modulo filtering 182 // 183 public static void copyTree(File src, File dst, Filter<File> filter) 184 throws IOException 185 { 186 ensureIsDirectory(src); 187 if (dst.exists()) { 188 if (!dst.isDirectory()) 189 delete(dst); 190 } else if (!dst.mkdirs()) 191 throw new IOException(dst + ": Cannot create directory"); 192 String[] sls = list(src); 193 for (int i = 0; i < sls.length; i++) { 194 File sf = new File(src, sls[i]); 195 if (filter != null && !filter.accept(sf)) 196 continue; 197 File df = new File(dst, sls[i]); 198 if (sf.isDirectory()) 199 copyTree(sf, df, filter); 200 else 201 copy(sf, df); 202 } 203 dst.setLastModified(src.lastModified()); 204 } 205 206 public static void copyTree(File src, File dst) 207 throws IOException 208 { 209 copyTree(src, dst, null); 210 } 211 212 private static void storeTree(File src, JarOutputStream dst, boolean deflate, 213 Filter<File> filter, String dstPath) 214 throws IOException 215 { 216 ensureIsDirectory(src); 217 String[] sls = list(src); 218 for (int i = 0; i < sls.length; i++) { 219 File sf = new File(src, sls[i]); 220 if (filter != null && !filter.accept(sf)) 221 continue; 222 String dp = (dstPath == null) ? sls[i] : dstPath + "/" + sls[i]; 223 if (sf.isDirectory()) { 224 storeTree(sf, dst, deflate, filter, dp); 225 } else { 226 ensureIsFile(sf); 227 try (OutputStream out = newOutputStream(dst, deflate, dp)) { 228 java.nio.file.Files.copy(sf.toPath(), out); 229 } 230 } 231 } 232 } 233 234 public static void storeTree(File src, JarOutputStream dst, boolean deflate, 235 Filter<File> filter) 236 throws IOException 237 { 238 storeTree(src, dst, deflate, filter, null); 239 } 240 241 public static void storeTree(File src, JarOutputStream dst, boolean deflate) 242 throws IOException 243 { 244 storeTree(src, dst, deflate, null, null); 245 } 246 247 public static interface Visitor<T> { 248 public void accept(T x) throws IOException; 249 } 250 251 public static void walkTree(File src, Visitor<File> visitor) 252 throws IOException 253 { 254 ensureIsDirectory(src); 255 String[] sls = list(src); 256 for (int i = 0; i < sls.length; i++) { 257 File sf = new File(src, sls[i]); 258 if (sf.isDirectory()) 259 walkTree(sf, visitor); 260 else 261 visitor.accept(sf); 262 } 263 } 264 265 public static byte[] load(InputStream is, int n) 266 throws IOException 267 { 268 DataInputStream in = new DataInputStream(is); 269 byte[] bs = new byte[n]; 270 try { 271 in.readFully(bs); 272 return bs; 273 } finally { 274 in.close(); 275 } 276 } 277 278 public static byte[] load(File src) 279 throws IOException 280 { 281 FileInputStream fis = new FileInputStream(src); 282 return load(fis, (int)src.length()); 283 } 284 285 public static void store(byte[] bs, File dst) 286 throws IOException 287 { 288 OutputStream out = new FileOutputStream(dst); 289 int n = bs.length; 290 try { 291 int i = 0; 292 while (i < n) { 293 int d = Math.min(n - i, 8192); 294 out.write(bs, i, d); 295 i += d; 296 } 297 } finally { 298 out.close(); 299 } 300 } 301 302 public static void mkdirs(File d, String what) 303 throws IOException 304 { 305 if (!d.mkdirs()) 306 throw new IOException(d + ": Cannot create " + what + " directory"); 307 } 308 309 private static class NonClosingInputStream 310 extends FilterInputStream 311 { 312 313 private NonClosingInputStream(InputStream out) { 314 super(out); 315 } 316 317 public void close() { } 318 319 } 320 321 public static InputStream nonClosingStream(InputStream out) { 322 return new NonClosingInputStream(out); 323 } 324 325 private static class JarEntryOutputStream 326 extends FilterOutputStream 327 { 328 329 CRC32 crc; 330 ByteArrayOutputStream baos; 331 CheckedOutputStream cos; 332 JarOutputStream jos; 333 boolean deflate; 334 String path; 335 336 private JarEntryOutputStream(JarOutputStream jos, 337 boolean deflate, 338 CRC32 crc, 339 ByteArrayOutputStream baos, 340 CheckedOutputStream cos, 341 String path) 342 { 343 super(cos); 344 this.jos = jos; 345 this.deflate = deflate; 346 this.crc = crc; 347 this.baos = baos; 348 this.cos = cos; 349 this.path = path; 350 } 351 352 public void close() throws IOException { 353 cos.close(); 354 JarEntry je = new JarEntry(path); 355 if (deflate) { 356 je.setMethod(JarEntry.DEFLATED); 357 } else { 358 je.setMethod(JarEntry.STORED); 359 je.setCrc(crc.getValue()); 360 je.setSize(baos.size()); 361 je.setCompressedSize(baos.size()); 362 } 363 jos.putNextEntry(je); 364 baos.writeTo(jos); 365 jos.closeEntry(); 366 } 367 368 } 369 370 public static JarEntryOutputStream 371 newOutputStream(JarOutputStream jos, boolean deflate, String path) 372 { 373 // Gee, dac, that zip API sure is broken, isn't it? 374 CRC32 crc = new CRC32(); 375 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 376 CheckedOutputStream cos = new CheckedOutputStream(baos, crc); 377 return new JarEntryOutputStream(jos, deflate, crc, baos, cos, path); 378 } 379 380 public static JarEntryOutputStream 381 newOutputStream(JarOutputStream jos, String path) 382 { 383 return newOutputStream(jos, false, path); 384 } 385 } --- EOF ---