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