1 /* 2 * Copyright (c) 2013, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package jdk.testlibrary; 25 26 import java.io.IOException; 27 import java.nio.file.DirectoryNotEmptyException; 28 import java.nio.file.FileVisitResult; 29 import java.nio.file.Files; 30 import java.nio.file.NoSuchFileException; 31 import java.nio.file.Path; 32 import java.nio.file.SimpleFileVisitor; 33 import java.nio.file.attribute.BasicFileAttributes; 34 import java.util.ArrayList; 35 import java.util.List; 36 37 38 /** 39 * Common library for various test file utility functions. 40 */ 41 public final class FileUtils { 42 43 private static final boolean isWindows = 44 System.getProperty("os.name").startsWith("Windows"); 45 private static final int RETRY_DELETE_MILLIS = isWindows ? 500 : 0; 46 private static final int MAX_RETRY_DELETE_TIMES = isWindows ? 15 : 0; 47 48 /** 49 * Deletes a file, retrying if necessary. 50 * 51 * @param path the file to delete 52 * 53 * @throws NoSuchFileException 54 * if the file does not exist (optional specific exception) 55 * @throws DirectoryNotEmptyException 56 * if the file is a directory and could not otherwise be deleted 57 * because the directory is not empty (optional specific exception) 58 * @throws IOException 59 * if an I/O error occurs 60 */ 61 public static void deleteFileWithRetry(Path path) 62 throws IOException 63 { 64 try { 65 deleteFileWithRetry0(path); 66 } catch (InterruptedException x) { 67 // Restore the interrupted status 68 Thread.currentThread().interrupt(); 69 } 70 } 71 72 private static void deleteFileWithRetry0(Path path) 73 throws IOException, InterruptedException 74 { 75 int times = 0; 76 IOException ioe = null; 77 while (true) { 78 try { 79 Files.delete(path); 80 break; 81 } catch (NoSuchFileException | DirectoryNotEmptyException x) { 82 throw x; 83 } catch (IOException x) { 84 // Backoff/retry in case another process is accessing the file 85 times++; 86 if (ioe == null) 87 ioe = x; 88 else 89 ioe.addSuppressed(x); 90 if (times > MAX_RETRY_DELETE_TIMES) 91 throw ioe; 92 Thread.sleep(RETRY_DELETE_MILLIS); 93 } 94 } 95 } 96 97 /** 98 * Deletes a directory and its subdirectories, retrying if necessary. 99 * 100 * @param dir the directory to delete 101 * 102 * @throws IOException 103 * If an I/O error occurs. Any such exceptions are caught 104 * internally. If only one is caught, then it is re-thrown. 105 * If more than one exception is caught, then the second and 106 * following exceptions are added as suppressed exceptions of the 107 * first one caught, which is then re-thrown. 108 */ 109 public static void deleteFileTreeWithRetry(Path dir) 110 throws IOException 111 { 112 IOException ioe = null; 113 final List<IOException> excs = deleteFileTreeUnchecked(dir); 114 if (!excs.isEmpty()) { 115 ioe = excs.remove(0); 116 for (IOException x : excs) 117 ioe.addSuppressed(x); 118 } 119 if (ioe != null) 120 throw ioe; 121 } 122 123 public static List<IOException> deleteFileTreeUnchecked(Path dir) { 124 final List<IOException> excs = new ArrayList<>(); 125 try { 126 java.nio.file.Files.walkFileTree(dir, new SimpleFileVisitor<Path>() { 127 @Override 128 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { 129 try { 130 deleteFileWithRetry0(file); 131 } catch (IOException x) { 132 excs.add(x); 133 } catch (InterruptedException x) { 134 // Restore the interrupted status and terminate 135 Thread.currentThread().interrupt(); 136 return FileVisitResult.TERMINATE; 137 } 138 return FileVisitResult.CONTINUE; 139 } 140 @Override 141 public FileVisitResult postVisitDirectory(Path dir, IOException exc) { 142 try { 143 deleteFileWithRetry0(dir); 144 } catch (IOException x) { 145 excs.add(x); 146 } catch (InterruptedException x) { 147 // Restore the interrupted status and terminate 148 Thread.currentThread().interrupt(); 149 return FileVisitResult.TERMINATE; 150 } 151 return FileVisitResult.CONTINUE; 152 } 153 @Override 154 public FileVisitResult visitFileFailed(Path file, IOException exc) { 155 excs.add(exc); 156 return FileVisitResult.CONTINUE; 157 } 158 }); 159 } catch (IOException x) { 160 excs.add(x); 161 } 162 return excs; 163 } 164 } 165