1 /* 2 * Copyright (c) 2014, 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 import java.io.ByteArrayInputStream; 24 import java.io.ByteArrayOutputStream; 25 import java.io.File; 26 import java.io.FilePermission; 27 import java.io.IOException; 28 import java.nio.channels.FileChannel; 29 import java.nio.file.Files; 30 import java.nio.file.Paths; 31 import static java.nio.file.StandardOpenOption.CREATE_NEW; 32 import static java.nio.file.StandardOpenOption.WRITE; 33 import java.security.CodeSource; 34 import java.security.Permission; 35 import java.security.PermissionCollection; 36 import java.security.Permissions; 37 import java.security.Policy; 38 import java.security.ProtectionDomain; 39 import java.util.Arrays; 40 import java.util.Collections; 41 import java.util.Enumeration; 42 import java.util.List; 43 import java.util.Properties; 44 import java.util.PropertyPermission; 45 import java.util.UUID; 46 import java.util.concurrent.atomic.AtomicBoolean; 47 import java.util.logging.FileHandler; 48 import java.util.logging.LogManager; 49 import java.util.logging.LoggingPermission; 50 51 /** 52 * @test 53 * @bug 8059269 54 * @summary tests that using a simple (non composite) pattern does not lead 55 * to NPE when the lock file already exists. 56 * @run main/othervm FileHandlerPath UNSECURE 57 * @run main/othervm FileHandlerPath SECURE 58 * @author danielfuchs 59 * @key randomness 60 */ 61 public class FileHandlerPath { 62 63 /** 64 * We will test the simple pattern in two configurations. 65 * UNSECURE: No security manager. 66 * SECURE: With the security manager present - and the required 67 * permissions granted. 68 */ 69 public static enum TestCase { 70 UNSECURE, SECURE; 71 public void run(Properties propertyFile) throws Exception { 72 System.out.println("Running test case: " + name()); 73 Configure.setUp(this, propertyFile); 74 test(this.name() + " " + propertyFile.getProperty("test.name"), propertyFile); 75 } 76 } 77 78 79 // Use a random name provided by UUID to avoid collision with other tests 80 final static String logFile = FileHandlerPath.class.getSimpleName() + "_" 81 + UUID.randomUUID().toString() + ".log"; 82 final static String tmpLogFile; 83 final static String userDir = System.getProperty("user.dir"); 84 final static String tmpDir = System.getProperty("java.io.tmpdir"); 85 private static final List<Properties> properties; 86 static { 87 tmpLogFile = new File(tmpDir, logFile).toString(); 88 Properties props1 = new Properties(); 89 Properties props2 = new Properties(); 90 props1.setProperty("test.name", "relative file"); 91 props1.setProperty("test.file.name", logFile); 92 props1.setProperty(FileHandler.class.getName() + ".pattern", logFile); 93 props1.setProperty(FileHandler.class.getName() + ".count", "1"); 94 props2.setProperty("test.name", "absoluste file"); 95 props2.setProperty("test.file.name", tmpLogFile); 96 props2.setProperty(FileHandler.class.getName() + ".pattern", "%t/" + logFile); 97 props2.setProperty(FileHandler.class.getName() + ".count", "1"); 98 properties = Collections.unmodifiableList(Arrays.asList( 99 props1, 100 props2)); 101 } 102 103 public static void main(String... args) throws Exception { 104 105 if (args == null || args.length == 0) { 106 args = new String[] { 107 TestCase.UNSECURE.name(), 108 TestCase.SECURE.name(), 109 }; 110 } 111 112 // Sanity checks 113 114 if (!Files.isWritable(Paths.get(userDir))) { 115 throw new RuntimeException(userDir + 116 ": user.dir is not writable - can't run test."); 117 } 118 if (!Files.isWritable(Paths.get(tmpDir))) { 119 throw new RuntimeException(tmpDir + 120 ": java.io.tmpdir is not writable - can't run test."); 121 } 122 123 File[] files = { 124 new File(logFile), 125 new File(tmpLogFile), 126 new File(logFile+".1"), 127 new File(tmpLogFile+".1"), 128 new File(logFile+".lck"), 129 new File(tmpLogFile+".lck"), 130 new File(logFile+".1.lck"), 131 new File(tmpLogFile+".1.lck") 132 }; 133 134 for (File log : files) { 135 if (log.exists()) { 136 throw new Exception(log +": file already exists - can't run test."); 137 } 138 } 139 140 // Now start the real test 141 142 try { 143 for (String testName : args) { 144 for (Properties propertyFile : properties) { 145 TestCase test = TestCase.valueOf(testName); 146 test.run(propertyFile); 147 } 148 } 149 } finally { 150 // Cleanup... 151 Configure.doPrivileged(() -> { 152 for(File log : files) { 153 try { 154 final boolean isLockFile = log.getName().endsWith(".lck"); 155 // lock file should already be deleted, except if the 156 // test failed in exception. 157 // log file should all be present, except if the test 158 // failed in exception. 159 if (log.exists()) { 160 if (!isLockFile) { 161 System.out.println("deleting "+log.toString()); 162 } else { 163 System.err.println("deleting lock file "+log.toString()); 164 } 165 log.delete(); 166 } else { 167 if (!isLockFile) { 168 System.err.println(log.toString() + ": not found."); 169 } 170 } 171 } catch (Throwable t) { 172 // should not happen 173 t.printStackTrace(); 174 } 175 } 176 }); 177 } 178 } 179 180 static class Configure { 181 static Policy policy = null; 182 static final AtomicBoolean allowAll = new AtomicBoolean(false); 183 static void setUp(TestCase test, Properties propertyFile) { 184 switch (test) { 185 case SECURE: 186 if (policy == null && System.getSecurityManager() != null) { 187 throw new IllegalStateException("SecurityManager already set"); 188 } else if (policy == null) { 189 policy = new SimplePolicy(TestCase.SECURE, allowAll); 190 Policy.setPolicy(policy); 191 System.setSecurityManager(new SecurityManager()); 192 } 193 if (System.getSecurityManager() == null) { 194 throw new IllegalStateException("No SecurityManager."); 195 } 196 if (policy == null) { 197 throw new IllegalStateException("policy not configured"); 198 } 199 break; 200 case UNSECURE: 201 if (System.getSecurityManager() != null) { 202 throw new IllegalStateException("SecurityManager already set"); 203 } 204 break; 205 default: 206 new InternalError("No such testcase: " + test); 207 } 208 doPrivileged(() -> { 209 try { 210 ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 211 propertyFile.store(bytes, propertyFile.getProperty("test.name")); 212 ByteArrayInputStream bais = new ByteArrayInputStream(bytes.toByteArray()); 213 LogManager.getLogManager().readConfiguration(bais); 214 } catch (IOException ex) { 215 throw new RuntimeException(ex); 216 } 217 }); 218 } 219 static void doPrivileged(Runnable run) { 220 allowAll.set(true); 221 try { 222 run.run(); 223 } finally { 224 allowAll.set(false); 225 } 226 } 227 } 228 229 public static void test(String name, Properties props) throws Exception { 230 System.out.println("Testing: " + name); 231 String file = props.getProperty("test.file.name"); 232 // create the lock files first - in order to take the path that 233 // used to trigger the NPE 234 Files.createFile(Paths.get(file + ".lck")); 235 Files.createFile(Paths.get(file + ".1.lck")); 236 final FileHandler f1 = new FileHandler(); 237 final FileHandler f2 = new FileHandler(); 238 f1.close(); 239 f2.close(); 240 System.out.println("Success for " + name); 241 } 242 243 244 final static class PermissionsBuilder { 245 final Permissions perms; 246 public PermissionsBuilder() { 247 this(new Permissions()); 248 } 249 public PermissionsBuilder(Permissions perms) { 250 this.perms = perms; 251 } 252 public PermissionsBuilder add(Permission p) { 253 perms.add(p); 254 return this; 255 } 256 public PermissionsBuilder addAll(PermissionCollection col) { 257 if (col != null) { 258 for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) { 259 perms.add(e.nextElement()); 260 } 261 } 262 return this; 263 } 264 public Permissions toPermissions() { 265 final PermissionsBuilder builder = new PermissionsBuilder(); 266 builder.addAll(perms); 267 return builder.perms; 268 } 269 } 270 271 public static class SimplePolicy extends Policy { 272 273 final Permissions permissions; 274 final Permissions allPermissions; 275 final AtomicBoolean allowAll; 276 public SimplePolicy(TestCase test, AtomicBoolean allowAll) { 277 this.allowAll = allowAll; 278 permissions = new Permissions(); 279 permissions.add(new LoggingPermission("control", null)); // needed by new FileHandler() 280 permissions.add(new FilePermission("<<ALL FILES>>", "read")); // needed by new FileHandler() 281 permissions.add(new FilePermission(logFile, "write,delete")); // needed by new FileHandler() 282 permissions.add(new FilePermission(logFile+".lck", "write,delete")); // needed by FileHandler.close() 283 permissions.add(new FilePermission(logFile+".1", "write,delete")); // needed by new FileHandler() 284 permissions.add(new FilePermission(logFile+".1.lck", "write,delete")); // needed by FileHandler.close() 285 permissions.add(new FilePermission(tmpLogFile, "write,delete")); // needed by new FileHandler() 286 permissions.add(new FilePermission(tmpLogFile+".lck", "write,delete")); // needed by FileHandler.close() 287 permissions.add(new FilePermission(tmpLogFile+".1", "write,delete")); // needed by new FileHandler() 288 permissions.add(new FilePermission(tmpLogFile+".1.lck", "write,delete")); // needed by FileHandler.close() 289 permissions.add(new FilePermission(userDir, "write")); // needed by new FileHandler() 290 permissions.add(new FilePermission(tmpDir, "write")); // needed by new FileHandler() 291 permissions.add(new PropertyPermission("user.dir", "read")); 292 permissions.add(new PropertyPermission("java.io.tmpdir", "read")); 293 allPermissions = new Permissions(); 294 allPermissions.add(new java.security.AllPermission()); 295 } 296 297 @Override 298 public boolean implies(ProtectionDomain domain, Permission permission) { 299 if (allowAll.get()) return allPermissions.implies(permission); 300 return permissions.implies(permission); 301 } 302 303 @Override 304 public PermissionCollection getPermissions(CodeSource codesource) { 305 return new PermissionsBuilder().addAll(allowAll.get() 306 ? allPermissions : permissions).toPermissions(); 307 } 308 309 @Override 310 public PermissionCollection getPermissions(ProtectionDomain domain) { 311 return new PermissionsBuilder().addAll(allowAll.get() 312 ? allPermissions : permissions).toPermissions(); 313 } 314 } 315 316 }