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> deleteTreeUnchecked(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(x); 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(x); 142 } 143 return FileVisitResult.CONTINUE; 144 } 145 @Override 146 public FileVisitResult visitFileFailed(Path file, IOException exc) { 147 excs.add(new IOException(exc)); 148 return FileVisitResult.CONTINUE; 149 } 150 }); 151 } catch (IOException x) { 152 excs.add(x); 153 } 154 return excs; 155 } 156 157 private static void copy(File src, File dst) 158 throws IOException 159 { 160 java.nio.file.Files.copy(src.toPath(), dst.toPath(), 161 COPY_ATTRIBUTES, REPLACE_EXISTING); 162 } 163 164 public static interface Filter<T> { 165 public boolean accept(T x) throws IOException; 166 } 167 168 // src, dst are directories 169 // src must exist; dst created if it does not yet exist 170 // Copy files from src to dst, modulo filtering 171 // 172 public static void copyTree(File src, File dst, Filter<File> filter) 173 throws IOException 174 { 175 ensureIsDirectory(src); 176 if (dst.exists()) { 177 if (!dst.isDirectory()) 178 delete(dst); 179 } else if (!dst.mkdirs()) 180 throw new IOException(dst + ": Cannot create directory"); 181 String[] sls = list(src); 182 for (int i = 0; i < sls.length; i++) { 183 File sf = new File(src, sls[i]); 184 if (filter != null && !filter.accept(sf)) 185 continue; 186 File df = new File(dst, sls[i]); 187 if (sf.isDirectory()) 188 copyTree(sf, df, filter); 189 else 190 copy(sf, df); 191 } 192 dst.setLastModified(src.lastModified()); 193 } 194 195 public static void copyTree(File src, File dst) 196 throws IOException 197 { 198 copyTree(src, dst, null); 199 } 200 201 private static void storeTree(File src, JarOutputStream dst, boolean deflate, 202 Filter<File> filter, String dstPath) 203 throws IOException 204 { 205 ensureIsDirectory(src); 206 String[] sls = list(src); 207 for (int i = 0; i < sls.length; i++) { 208 File sf = new File(src, sls[i]); 209 if (filter != null && !filter.accept(sf)) 210 continue; 211 String dp = (dstPath == null) ? sls[i] : dstPath + "/" + sls[i]; 212 if (sf.isDirectory()) { 213 storeTree(sf, dst, deflate, filter, dp); 214 } else { 215 ensureIsFile(sf); 216 try (OutputStream out = newOutputStream(dst, deflate, dp)) { 217 java.nio.file.Files.copy(sf.toPath(), out); 218 } 219 } 220 } 221 } 222 223 public static void storeTree(File src, JarOutputStream dst, boolean deflate, 224 Filter<File> filter) 225 throws IOException 226 { 227 storeTree(src, dst, deflate, filter, null); 228 } 229 230 public static void storeTree(File src, JarOutputStream dst, boolean deflate) 231 throws IOException 232 { 233 storeTree(src, dst, deflate, null, null); 234 } 235 236 public static interface Visitor<T> { 237 public void accept(T x) throws IOException; 238 } 239 240 public static void walkTree(File src, Visitor<File> visitor) 241 throws IOException 242 { 243 ensureIsDirectory(src); 244 String[] sls = list(src); 245 for (int i = 0; i < sls.length; i++) { 246 File sf = new File(src, sls[i]); 247 if (sf.isDirectory()) 248 walkTree(sf, visitor); 249 else 250 visitor.accept(sf); 251 } 252 } 253 254 public static byte[] load(InputStream is, int n) 255 throws IOException 256 { 257 DataInputStream in = new DataInputStream(is); 258 byte[] bs = new byte[n]; 259 try { 260 in.readFully(bs); 261 return bs; 262 } finally { 263 in.close(); 264 } 265 } 266 267 public static byte[] load(File src) 268 throws IOException 269 { 270 FileInputStream fis = new FileInputStream(src); 271 return load(fis, (int)src.length()); 272 } 273 274 public static void store(byte[] bs, File dst) 275 throws IOException 276 { 277 OutputStream out = new FileOutputStream(dst); 278 int n = bs.length; 279 try { 280 int i = 0; 281 while (i < n) { 282 int d = Math.min(n - i, 8192); 283 out.write(bs, i, d); 284 i += d; 285 } 286 } finally { 287 out.close(); 288 } 289 } 290 291 public static void mkdirs(File d, String what) 292 throws IOException 293 { 294 if (!d.mkdirs()) 295 throw new IOException(d + ": Cannot create " + what + " directory"); 296 } 297 298 private static class NonClosingInputStream 299 extends FilterInputStream 300 { 301 302 private NonClosingInputStream(InputStream out) { 303 super(out); 304 } 305 306 public void close() { } 307 308 } 309 310 public static InputStream nonClosingStream(InputStream out) { 311 return new NonClosingInputStream(out); 312 } 313 314 private static class JarEntryOutputStream 315 extends FilterOutputStream 316 { 317 318 CRC32 crc; 319 ByteArrayOutputStream baos; 320 CheckedOutputStream cos; 321 JarOutputStream jos; 322 boolean deflate; 323 String path; 324 325 private JarEntryOutputStream(JarOutputStream jos, 326 boolean deflate, 327 CRC32 crc, 328 ByteArrayOutputStream baos, 329 CheckedOutputStream cos, 330 String path) 331 { 332 super(cos); 333 this.jos = jos; 334 this.deflate = deflate; 335 this.crc = crc; 336 this.baos = baos; 337 this.cos = cos; 338 this.path = path; 339 } 340 341 public void close() throws IOException { 342 cos.close(); 343 JarEntry je = new JarEntry(path); 344 if (deflate) { 345 je.setMethod(JarEntry.DEFLATED); 346 } else { 347 je.setMethod(JarEntry.STORED); 348 je.setCrc(crc.getValue()); 349 je.setSize(baos.size()); 350 je.setCompressedSize(baos.size()); 351 } 352 jos.putNextEntry(je); 353 baos.writeTo(jos); 354 jos.closeEntry(); 355 } 356 357 } 358 359 public static JarEntryOutputStream 360 newOutputStream(JarOutputStream jos, boolean deflate, String path) 361 { 362 // Gee, dac, that zip API sure is broken, isn't it? 363 CRC32 crc = new CRC32(); 364 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 365 CheckedOutputStream cos = new CheckedOutputStream(baos, crc); 366 return new JarEntryOutputStream(jos, deflate, crc, baos, cos, path); 367 } 368 369 public static JarEntryOutputStream 370 newOutputStream(JarOutputStream jos, String path) 371 { 372 return newOutputStream(jos, false, path); 373 } 374 } --- EOF ---